Skip to content

Commit

Permalink
DOC Update syntax for callout blocks (#455)
Browse files Browse the repository at this point in the history
  • Loading branch information
GuySartorelli committed Feb 2, 2024
1 parent b8fdfcb commit e5f5434
Show file tree
Hide file tree
Showing 7 changed files with 88 additions and 118 deletions.
43 changes: 20 additions & 23 deletions en/02_Developer_Guides/00_Model/02_Relations.md
Expand Up @@ -167,13 +167,12 @@ in situations like adding multiple lists of links to a [`SiteConfig`](api:Silver
An additional column is created called `<relationship-name>Relation`, along with the `<relationship-name>Class`
and `<relationship-name>ID` columns of a normal polymorphic `has_one` relation.

[warning]
If you save records into the `has_one` relation programatically, you must set the relation in the
`<relationship-name>Relation` field, or it won't be included when you fetch the `has_many` relation list.

Generally it is better to instead add the record with the `has_one` relation into its corresponding `has_many` relation
directly - see [adding relations](#adding-relations).
[/warning]
> [!WARNING]
> If you save records into the `has_one` relation programatically, you must set the relation in the
> `<relationship-name>Relation` field, or it won't be included when you fetch the `has_many` relation list.
>
> Generally it is better to instead add the record with the `has_one` relation into its corresponding `has_many` relation
> directly - see [adding relations](#adding-relations).
To specify that a `has_one` relation is multi-relational define the relation like so:

Expand All @@ -198,9 +197,8 @@ class Fan extends DataObject
}
```

[hint]
Multi-relational `has_one` relations *must* be [polymorphic](#polymorphic-has-one).
[/hint]
> [!TIP]
> Multi-relational `has_one` relations *must* be [polymorphic](#polymorphic-has-one).
It is best practice for your `has_many` relations to indicate which relation they're pointing at using dot notation. For example:

Expand Down Expand Up @@ -265,19 +263,18 @@ class Coach extends DataObject

Defines one-to-many joins. As you can see from the previous example, `$has_many` goes hand in hand with `$has_one`.

[alert]
When defining a `has_many` relation, you *must* specify a `has_one` relationship on the related class as well. To add a `has_one` relation on core classes, yml config settings can be used:

```yml
SilverStripe\Assets\Image:
has_one:
Team: App\Model\Team
```

You can point multiple `has_many` relations at a single `has_one` relation if you use a [multi-relational `has_one`](#multi-relational-has-one).

Note that in some cases you may be better off using a `many_many` relation instead. Carefully consider whether you are defining a "one-to-many" or a "many-to-many" relationship.
[/alert]
> [!CAUTION]
> When defining a `has_many` relation, you *must* specify a `has_one` relationship on the related class as well. To add a `has_one` relation on core classes, yml config settings can be used:
>
> ```yml
> SilverStripe\Assets\Image:
> has_one:
> Team: App\Model\Team
> ```
>
> You can point multiple `has_many` relations at a single `has_one` relation if you use a [multi-relational `has_one`](#multi-relational-has-one).
>
> Note that in some cases you may be better off using a `many_many` relation instead. Carefully consider whether you are defining a "one-to-many" or a "many-to-many" relationship.
```php
namespace App\Model;
Expand Down
25 changes: 10 additions & 15 deletions en/02_Developer_Guides/02_Controllers/07_CMS_JSON_APIs.md
Expand Up @@ -23,9 +23,8 @@ Because of this you should generally avoid updating large parts of a DataObject

Create a subclass of [`LeftAndMain`](api:SilverStripe\Admin\LeftAndMain). This ensures that users must be logged in to the admin interface to access the endpoint. Additionally, it provides access to the methods [`LeftAndMain::jsonSuccess()`](api:SilverStripe\Admin\LeftAndMain::jsonSuccess()) and [`LeftAndMain::jsonError()`](api:SilverStripe\Admin\LeftAndMain::jsonError()).

[warning]
To enhance security, do not create a direct subclass of [`Controller`](api:SilverStripe\Control\Controller) routed using YAML on the `/admin` route. This practice is strongly discouraged as it circumvents the requirement to log in to the CMS to access the endpoints. At best you'd be re-implementing logic that already exists.
[/warning]
> [!WARNING]
> To enhance security, do not create a direct subclass of [`Controller`](api:SilverStripe\Control\Controller) routed using YAML on the `/admin` route. This practice is strongly discouraged as it circumvents the requirement to log in to the CMS to access the endpoints. At best you'd be re-implementing logic that already exists.
When naming this class, it's best practice to add a "Controller" suffix to this class, for instance name it `MySomethingController`.

Expand Down Expand Up @@ -114,9 +113,8 @@ Generally you should not include a message outlining the nature of the error whe

If you do include a message, remember that error messages are only intended for developers so do not use the `_t()` function to make them translatable. Do not use any returned messages on the frontend for things like toast notifications, instead those messages should be added directly in JavaScript.

[info]
Despite the slightly convoluted JSON format returned by `jsonError()` with multiple nodes, its usage remains consistent with `FormSchema`. It's better to use this method for uniformity rather than introducing separate methods for `FormSchema` and non-FormSchema failures.
[/info]
> [!NOTE]
> Despite the slightly convoluted JSON format returned by `jsonError()` with multiple nodes, its usage remains consistent with `FormSchema`. It's better to use this method for uniformity rather than introducing separate methods for `FormSchema` and non-FormSchema failures.
## CSRF token

Expand All @@ -130,9 +128,8 @@ import Config from 'lib/Config';
const securityID = Config.get('SecurityID');
```

[warning]
The `lib/Config` import is provided by the `silverstripe/admin` module via [`@silverstripe/webpack-config`](https://www.npmjs.com/package/@silverstripe/webpack-config).
[/warning]
> [!WARNING]
> The `lib/Config` import is provided by the `silverstripe/admin` module via [`@silverstripe/webpack-config`](https://www.npmjs.com/package/@silverstripe/webpack-config).
Ensure the security of your endpoints by validating the security token on relevant endpoints.

Expand All @@ -144,9 +141,8 @@ if (!SecurityToken::inst()->checkRequest($this->getRequest())) {
}
```

[info]
The `400` HTTP status code used here is consistent with the code used when the CSRF check fails when submitting data using `FormSchema`.
[/info]
> [!NOTE]
> The `400` HTTP status code used here is consistent with the code used when the CSRF check fails when submitting data using `FormSchema`.
## Passing values from PHP to global JavaScript

Expand Down Expand Up @@ -211,9 +207,8 @@ backend.post(endpoint, data, headers)
});
```

[warning]
The `lib/Config` and `lib/Backend` imports are provided by the `silverstripe/admin` module via [`@silverstripe/webpack-config`](https://www.npmjs.com/package/@silverstripe/webpack-config).
[/warning]
> [!WARNING]
> The `lib/Config` and `lib/Backend` imports are provided by the `silverstripe/admin` module via [`@silverstripe/webpack-config`](https://www.npmjs.com/package/@silverstripe/webpack-config).
On the controller's endpoint method, retrieve the POST data using `$json = json_decode($this->getRequest()->getBody());`.

Expand Down
Expand Up @@ -8,9 +8,8 @@ icon: table

[`GridField`](api:SilverStripe\Forms\GridField\GridField) is often used for displaying and editing `DataObject` records - but it can be used with other data as well. You might have data that is pulled from an API for example, which you want to display in the admin area of your Silverstripe CMS project.

[info]
This document assumes you're familiar with `GridField` - see the [`GridField` documentation](/developer_guides/forms/field_types/gridfield/) for information about using `GridField`.
[/info]
> [!NOTE]
> This document assumes you're familiar with `GridField` - see the [`GridField` documentation](/developer_guides/forms/field_types/gridfield/) for information about using `GridField`.
Data which isn't represented by `DataObject` records can come in two forms:

Expand All @@ -25,11 +24,10 @@ Some grid field components may require specific information, such as which colum

Regardless of how you get your data, whether it's from a web API or some other source, you'll need to store it in an `ArrayList`. For best results, each record should also be explicitly instantiated as an `ArrayData` object in the list.

[hint]
The `ID` field shown here isn't necessary if you only want to view the records as rows in the `GridField`, but if you want to be able to view *each* record in a read-only form view, the `ID` field is mandatory.

See [viewing data in a form](#arraydata-view) for more information.
[/hint]
> [!TIP]
> The `ID` field shown here isn't necessary if you only want to view the records as rows in the `GridField`, but if you want to be able to view *each* record in a read-only form view, the `ID` field is mandatory.
>
> See [viewing data in a form](#arraydata-view) for more information.
```php
use SilverStripe\ORM\ArrayList;
Expand Down Expand Up @@ -116,9 +114,8 @@ For data to be viewed in a read-only form, each record in the list must have an

You'll need to add a `GridFieldDetailForm` component to the `GridField` and tell it how to represent your data by passing a [`FieldList`](api:SilverStripe\Forms\FieldList) into [`GridFieldDetailForm::setFields()`](api:SilverStripe\Forms\GridField\GridFieldDetailForm::setFields()).

[hint]
Because `ArrayData` doesn't implement a `canEdit()` method, the form will be implicitly turned into a read-only form for you. You don't need to worry about passing in read-only form fields.
[/hint]
> [!TIP]
> Because `ArrayData` doesn't implement a `canEdit()` method, the form will be implicitly turned into a read-only form for you. You don't need to worry about passing in read-only form fields.
```php
use SilverStripe\Forms\FieldList;
Expand Down Expand Up @@ -151,11 +148,10 @@ However, if you omit these method implementations, you must instead pass the req

To represent your data as rows in a `GridField`, you can rely on the default `GridFieldConfig` object that the field will build for itself. If you implement a `summaryFields()` method in your data class, the `GridField` will call that method to find out what fields it should display.

[hint]
The `ID` field shown here isn't necessary if you only want to view/edit the records as rows in the `GridField`, but if you want to be able to view *each* record in a read-only form view, the `ID` field is mandatory.

See [viewing data in a form](#custom-view) for more information.
[/hint]
> [!TIP]
> The `ID` field shown here isn't necessary if you only want to view/edit the records as rows in the `GridField`, but if you want to be able to view *each* record in a read-only form view, the `ID` field is mandatory.
>
> See [viewing data in a form](#custom-view) for more information.
```php
namespace App\Data;
Expand Down Expand Up @@ -221,9 +217,8 @@ If you want to be able to filter your `GridField`, you will need to tell the `Gr

What's more, we don't have to pass the search fields into the `BasicSearchContext` instance either if we implement a `scaffoldSearchFields()` method.

[hint]
You can optionally implement the `i18n_singular_name()` method to return a localised string to represent the plural name of this model. This is used in the filter header as the placeholder text for the general search field.
[/hint]
> [!TIP]
> You can optionally implement the `i18n_singular_name()` method to return a localised string to represent the plural name of this model. This is used in the filter header as the placeholder text for the general search field.
```php
namespace App\Data;
Expand Down Expand Up @@ -257,9 +252,8 @@ class DataRepresentation extends ViewableData

No changes are required to the `GridField` components, assuming you didn't remove the `GridFieldFilterHeader` component.

[hint]
The `BasicSearchContext` respects some (*but not all*) [`$searchable_fields` configuration options](/developer_guides/model/scaffolding/#searchable-fields), so you can implement a `searchableFields()` method in your class to further customise the `GridField` filtering experience.
[/hint]
> [!TIP]
> The `BasicSearchContext` respects some (*but not all*) [`$searchable_fields` configuration options](/developer_guides/model/scaffolding/#searchable-fields), so you can implement a `searchableFields()` method in your class to further customise the `GridField` filtering experience.
### Exporting data {#custom-export}

Expand All @@ -282,9 +276,8 @@ If the class representing your data has a `getCMSFields()` method, the return va

If your class doesn't implement a `canEdit()` method, or it does and the method returns `false`, the form will be read-only.

[hint]
You can optionally implement the `i18n_plural_name()` method to return a localised string to represent the singular name of this model. This is used in the add button, breadcrumbs, and toasts.
[/hint]
> [!TIP]
> You can optionally implement the `i18n_plural_name()` method to return a localised string to represent the singular name of this model. This is used in the add button, breadcrumbs, and toasts.
```php
namespace App\Data;
Expand Down Expand Up @@ -332,9 +325,8 @@ For new records, the `write()` method *must* set the `ID` field on the record, s

Records with no `ID` field or which have a non-numeric value for their `ID` field are considered new (unsaved) records.

[hint]
If you have specific validation rules you want to apply, you can also implement a `getCMSCompositeValidator()` method as described in [validation in the CMS](/developer_guides/forms/validation/#validation-in-the-cms).
[/hint]
> [!TIP]
> If you have specific validation rules you want to apply, you can also implement a `getCMSCompositeValidator()` method as described in [validation in the CMS](/developer_guides/forms/validation/#validation-in-the-cms).
```php
namespace App\Data;
Expand Down Expand Up @@ -421,13 +413,11 @@ $gridField->getConfig()->addComponent(GridFieldEditButton::create());

You can also enable creating new records and deleting records by adding the [`GridFieldAddNewButton`](api:SilverStripe\Forms\GridField\GridFieldAddNewButton) and [`GridFieldDeleteAction`](api:SilverStripe\Forms\GridField\GridFieldDeleteAction) components to your `GridField` config.

[hint]
At this point your `GridField` config is essentially the same as a [`GridFieldConfig_RecordEditor`](api:SilverStripe\Forms\GridField\GridFieldConfig_RecordEditor) - so you could set up your `GridField` like so:

```php
use SilverStripe\Forms\GridField\GridField;
use SilverStripe\Forms\GridField\GridFieldConfig_RecordEditor;
$gridField = GridField::create('MyData', 'My data', $list, GridFieldConfig_RecordEditor::create());
```

[/hint]
> [!TIP]
> At this point your `GridField` config is essentially the same as a [`GridFieldConfig_RecordEditor`](api:SilverStripe\Forms\GridField\GridFieldConfig_RecordEditor) - so you could set up your `GridField` like so:
>
> ```php
> use SilverStripe\Forms\GridField\GridField;
> use SilverStripe\Forms\GridField\GridFieldConfig_RecordEditor;
> $gridField = GridField::create('MyData', 'My data', $list, GridFieldConfig_RecordEditor::create());
> ```
29 changes: 12 additions & 17 deletions en/02_Developer_Guides/03_Forms/Field_types/04_GridField.md
Expand Up @@ -13,10 +13,9 @@ Usually `GridField` is used with `DataObject` records - but it can be used with

See [using `GridField` with arbitrary data](/developer_guides/forms/using_gridfield_with_arbitrary_data/) for more information.

[info]
`GridField` powers the automated data UI of [ModelAdmin](api:SilverStripe\Admin\ModelAdmin). For more information about `ModelAdmin` see the
[Customizing the CMS](/developer_guides/customising_the_admin_interface) guide.
[/info]
> [!NOTE]
> `GridField` powers the automated data UI of [ModelAdmin](api:SilverStripe\Admin\ModelAdmin). For more information about `ModelAdmin` see the
> [Customizing the CMS](/developer_guides/customising_the_admin_interface) guide.
```php
use SilverStripe\Forms\GridField\GridField;
Expand Down Expand Up @@ -221,12 +220,11 @@ $gridField->setConfig($config);
Similar to `GridFieldConfig_Base` with the addition support of the ability to view a [`GridFieldDetailForm`](api:SilverStripe\Forms\GridField\GridFieldDetailForm) containing
a read-only view of the data record.

[info]
Each record in the list must have an `ID` field, and the value of that field must be a positive integer.

If the class representing your data has a `getCMSFields()` method, the return value of that method will be used for the fields displayed in the read-only view.
Otherwise, you'll need to pass in a [`FieldList`](api:SilverStripe\Forms\FieldList) to [`GridFieldDetailForm::setFields()`](api:SilverStripe\Forms\GridField\GridFieldDetailForm::setFields()).
[/info]
> [!NOTE]
> Each record in the list must have an `ID` field, and the value of that field must be a positive integer.
>
> If the class representing your data has a `getCMSFields()` method, the return value of that method will be used for the fields displayed in the read-only view.
> Otherwise, you'll need to pass in a [`FieldList`](api:SilverStripe\Forms\FieldList) to [`GridFieldDetailForm::setFields()`](api:SilverStripe\Forms\GridField\GridFieldDetailForm::setFields()).
```php
use SilverStripe\Forms\GridField\GridFieldConfig_RecordViewer;
Expand All @@ -246,18 +244,15 @@ $gridField->setConfig($config);
Similar to `GridFieldConfig_RecordViewer` with the addition support to edit or delete each of the records.

[info]
Each record in the list must have an `ID` field, and the value of that field must be a positive integer.

If the class representing your data has a `getCMSFields()` method, the return value of that method will be used for the fields displayed in the read-only view.
Otherwise, you'll need to pass in a [`FieldList`](api:SilverStripe\Forms\FieldList) to [`GridFieldDetailForm::setFields()`](api:SilverStripe\Forms\GridField\GridFieldDetailForm::setFields()).
[/info]

[warning]
The class representing your data *must* implement [`DataObjectInterface`](api:SilverStripe\ORM\DataObjectInterface) so that your records can be edited.

See [using `GridField` with arbitrary data](/developer_guides/forms/using_gridfield_with_arbitrary_data/) for more information.
[/warning]
> [!WARNING]
> The class representing your data *must* implement [`DataObjectInterface`](api:SilverStripe\ORM\DataObjectInterface) so that your records can be edited.
>
> See [using `GridField` with arbitrary data](/developer_guides/forms/using_gridfield_with_arbitrary_data/) for more information.
```php
use SilverStripe\Forms\GridField\GridFieldConfig_RecordEditor;
Expand Down
5 changes: 2 additions & 3 deletions en/02_Developer_Guides/11_Integration/00_CSV_Import.md
Expand Up @@ -91,9 +91,8 @@ Let's create a simple upload form (which is used for `MyDataObject` instances).
You'll need to add a route to your controller to make it accessible via URL
(see [Routing](../../controllers/routing/)).

[warning]
Don't forget to perform [permission checks](#permission-checks) if the data is provided by users.
[/warning]
> [!WARNING]
> Don't forget to perform [permission checks](#permission-checks) if the data is provided by users.
```php
namespace App\Control;
Expand Down
Expand Up @@ -81,6 +81,5 @@ class MyController extends Controller
}
```

[alert]
If the file you're loading data from is uploaded by a user, you should pass `true` to the [`CsvBulkLoader::setCheckPermissions()`](api:SilverStripe\Dev\CsvBulkLoader::setCheckPermissions()) method. Otherwise, permissions will not be respected and the user may alter data in ways they would otherwise not be permitted to.
[/alert]
> [!CAUTION]
> If the file you're loading data from is uploaded by a user, you should pass `true` to the [`CsvBulkLoader::setCheckPermissions()`](api:SilverStripe\Dev\CsvBulkLoader::setCheckPermissions()) method. Otherwise, permissions will not be respected and the user may alter data in ways they would otherwise not be permitted to.

0 comments on commit e5f5434

Please sign in to comment.