diff --git a/en/00_Getting_Started/00_Server_Requirements.md b/en/00_Getting_Started/00_Server_Requirements.md index 6c080e3f2..3cae3e95f 100644 --- a/en/00_Getting_Started/00_Server_Requirements.md +++ b/en/00_Getting_Started/00_Server_Requirements.md @@ -101,9 +101,8 @@ also needs write access for the webserver user to the following locations: [schema introspection](/developer_guides/graphql/tips_and_tricks#schema-introspection). You should treat this folder the same way you treat the `.graphql-generated` folder. -[info] -If you are still using silverstripe/graphql 3.x, you do not need the `.graphql-generated` or `public/_graphql` directories. -[/info] +> [!NOTE] +> If you are still using silverstripe/graphql 3.x, you do not need the `.graphql-generated` or `public/_graphql` directories. If you aren't explicitly [packaging](#building-packaging-deployment) your Silverstripe CMS project during your deployment process, additional write access may be required to generate supporting diff --git a/en/00_Getting_Started/02_Composer.md b/en/00_Getting_Started/02_Composer.md index fcf5c803f..80446331c 100644 --- a/en/00_Getting_Started/02_Composer.md +++ b/en/00_Getting_Started/02_Composer.md @@ -70,11 +70,10 @@ a [version constraint](http://getcomposer.org/doc/01-basic-usage.md#the-require- composer require silverstripe/blog ^2 ``` -[warning] -**Version constraints:** `master` is not a legal version string - it's a branch name. These are different things. The -version string that would get you the branch is `dev-master`. The version string that would get you a numeric branch is -a little different. The version string for the `4` branch is `4.x-dev`. -[/warning] +> [!WARNING] +> **Version constraints:** `master` is not a legal version string - it's a branch name. These are different things. The +> version string that would get you the branch is `dev-master`. The version string that would get you a numeric branch is +> a little different. The version string for the `4` branch is `4.x-dev`. ## Updating dependencies diff --git a/en/00_Getting_Started/03_Environment_Management.md b/en/00_Getting_Started/03_Environment_Management.md index e9eaa7329..90cfcebd5 100644 --- a/en/00_Getting_Started/03_Environment_Management.md +++ b/en/00_Getting_Started/03_Environment_Management.md @@ -56,9 +56,8 @@ use SilverStripe\Core\Environment; Environment::setEnv('API_KEY', 'AABBCCDDEEFF012345'); ``` -[warning] -`Environment::getEnv()` will return `false` whether the variable was explicitly set as `false` or simply wasn't set at all. You can use [`Environment::hasEnv()`](api:SilverStripe\Core\Environment::hasEnv()) to check whether an environment variable was set or not. -[/warning] +> [!WARNING] +> `Environment::getEnv()` will return `false` whether the variable was explicitly set as `false` or simply wasn't set at all. You can use [`Environment::hasEnv()`](api:SilverStripe\Core\Environment::hasEnv()) to check whether an environment variable was set or not. ### Using environment variables in config @@ -74,9 +73,8 @@ SilverStripe\Core\Injector\Injector: ThisWillNotSubstitute: 'lorem `REGULAR_TEXT` ipsum' ``` -[info] -Environment variables cannot be used outside of Injector config as of version 4.2. -[/info] +> [!NOTE] +> Environment variables cannot be used outside of Injector config as of version 4.2. ## Including an extra `.env` file diff --git a/en/02_Developer_Guides/00_Model/01_Data_Model_and_ORM.md b/en/02_Developer_Guides/00_Model/01_Data_Model_and_ORM.md index ce9efee4e..e83915633 100644 --- a/en/02_Developer_Guides/00_Model/01_Data_Model_and_ORM.md +++ b/en/02_Developer_Guides/00_Model/01_Data_Model_and_ORM.md @@ -63,10 +63,9 @@ It **won't** do any of the following - Rename any tables that it doesn't recognize. This allows other applications to coexist in the same database, as long as their table names don't match a Silverstripe CMS data class. -[notice] -You need to be logged in as an administrator to perform this command, unless your site is in [dev mode](../debugging), -or the command is run through [CLI](../cli). -[/notice] +> [!WARNING] +> You need to be logged in as an administrator to perform this command, unless your site is in [dev mode](../debugging), +> or the command is run through [CLI](../cli). When rebuilding the database schema through the [ClassLoader](api:SilverStripe\Core\Manifest\ClassLoader) the following additional properties are automatically set on the `DataObject`. @@ -127,9 +126,8 @@ Or, a better way is to use the `create` method. $player = Player::create(); ``` -[notice] -Using the `create()` method provides chainability, which can add elegance and brevity to your code, e.g. `Player::create()->write()`. More importantly, however, it will look up the class in the [Injector](../extending/injector) so that the class can be overridden by [dependency injection](http://en.wikipedia.org/wiki/Dependency_injection). -[/notice] +> [!WARNING] +> Using the `create()` method provides chainability, which can add elegance and brevity to your code, e.g. `Player::create()->write()`. More importantly, however, it will look up the class in the [Injector](../extending/injector) so that the class can be overridden by [dependency injection](http://en.wikipedia.org/wiki/Dependency_injection). Database columns and properties can be set as class properties on the object. The Silverstripe CMS ORM handles the saving of the values through a custom `__set()` method. @@ -175,6 +173,9 @@ echo $player->dbObject('LastEdited')->Ago(); The `ORM` uses a "fluent" syntax, where you specify a query by chaining together different methods. Two common methods are `filter()` and `sort()`: +> [!NOTE] +> Provided `filter` values are automatically escaped and do not require any escaping. + ```php $members = Player::get()->filter([ 'FirstName' => 'Sam', @@ -183,15 +184,10 @@ $members = Player::get()->filter([ // returns a `DataList` containing all the `Player` records that have the `FirstName` of 'Sam' ``` -[info] -Provided `filter` values are automatically escaped and do not require any escaping. -[/info] - -[info] -`DataObject::get()->byID()` and `DataObject::get_by_id()` achieve similar results, but the object returned by `DataObject::get_by_id()` is cached against a `static` property within `DataObject`. - -`DataObject::get_by_id()` is a legacy ORM method, and it is recommended that you use `DataObject::get()->byID()` wherever possible -[/info] +> [!NOTE] +> `DataObject::get()->byID()` and `DataObject::get_by_id()` achieve similar results, but the object returned by `DataObject::get_by_id()` is cached against a `static` property within `DataObject`. +> +> `DataObject::get_by_id()` is a legacy ORM method, and it is recommended that you use `DataObject::get()->byID()` wherever possible ## Lazy loading @@ -445,11 +441,10 @@ $teams = Team::get()->filter('Players.Sum(PointsScored):LessThan', 300); It is also possible to filter by a PHP callback, this will force the data model to fetch all records and loop them in PHP, thus `filter()` or `filterAny()` are to be preferred over `filterByCallback()`. -[notice] -Because `filterByCallback()` has to run in PHP, it has a significant performance tradeoff, and should not be used on large recordsets. - -`filterByCallback()` will always return an `ArrayList`. -[/notice] +> [!WARNING] +> Because `filterByCallback()` has to run in PHP, it has a significant performance tradeoff, and should not be used on large recordsets. +> +> `filterByCallback()` will always return an `ArrayList`. The first parameter to the callback is the item, the second parameter is the list itself. The callback will run once for each record, if the callback returns true, this record will be added to the list of returned items. @@ -557,9 +552,8 @@ offset, if not provided as an argument, will default to 0. $members = Member::get()->sort('Surname')->limit(10, 4); ``` -[alert] -Note that the `limit` argument order is different from a MySQL LIMIT clause. -[/alert] +> [!CAUTION] +> Note that the `limit` argument order is different from a MySQL LIMIT clause. ### Mapping classes to tables with `DataObjectSchema` @@ -657,10 +651,9 @@ $members = Member::get() ->innerJoin('Group_Members', '"Rel"."MemberID" = "Member"."ID"', 'Rel'); ``` -[alert] -Passing a *$join* statement will filter results further by the JOINs performed against the foreign table. It will -**not** return the additionally joined data. -[/alert] +> [!CAUTION] +> Passing a *$join* statement will filter results further by the JOINs performed against the foreign table. It will +> **not** return the additionally joined data. ### Default values @@ -680,10 +673,9 @@ class Player extends DataObject } ``` -[notice] -Note: Alternatively you can set defaults directly in the database-schema (rather than the object-model). See -[Data Types and Casting](/developer_guides/model/data_types_and_casting) for details. -[/notice] +> [!WARNING] +> Note: Alternatively you can set defaults directly in the database-schema (rather than the object-model). See +> [Data Types and Casting](/developer_guides/model/data_types_and_casting) for details. ## Subclasses diff --git a/en/02_Developer_Guides/00_Model/02_Relations.md b/en/02_Developer_Guides/00_Model/02_Relations.md index 27167a8ba..78692331d 100644 --- a/en/02_Developer_Guides/00_Model/02_Relations.md +++ b/en/02_Developer_Guides/00_Model/02_Relations.md @@ -148,29 +148,26 @@ class Fan extends DataObject } ``` -[warning] -Note: The use of polymorphic relationships can affect query performance, especially -on joins, and also increases the complexity of the database and necessary user code. -They should be used sparingly, and only where additional complexity would otherwise -be necessary. For example additional parent classes for each respective relationship, or -duplication of code. -[/warning] +> [!WARNING] +> Note: The use of polymorphic relationships can affect query performance, especially +> on joins, and also increases the complexity of the database and necessary user code. +> They should be used sparingly, and only where additional complexity would otherwise +> be necessary. For example additional parent classes for each respective relationship, or +> duplication of code. ## `has_many` Defines 1-to-many joins. As you can see from the previous example, `$has_many` goes hand in hand with `$has_one`. -[alert] -Please specify a $has_one-relationship on the related child-class as well, in order to have the necessary accessors -available on both ends. To add a $has_one-relationship on core classes, yml config settings can be used: - -```yml -SilverStripe\Assets\Image: - has_one: - App\Model\MyDataObject: MyDataObject -``` - -[/alert] +> [!CAUTION] +> Please specify a $has_one-relationship on the related child-class as well, in order to have the necessary accessors +> available on both ends. To add a $has_one-relationship on core classes, yml config settings can be used: +> +> ```yml +> SilverStripe\Assets\Image: +> has_one: +> App\Model\MyDataObject: MyDataObject +> ``` ```php namespace App\Model; @@ -324,18 +321,16 @@ Defines many-to-many joins, which uses a third table created between the two to There are two ways in which this can be declared, which are described below, depending on how the developer wishes to manage this join table. -[warning] -Please specify a $belongs_many_many-relationship on the related class as well, in order -to have the necessary accessors available on both ends. You can use `RelationValidationService` for validation of relationships. This tool will point out the relationships which may need a review. - -Example configuration: - -```yml -SilverStripe\Dev\Validation\RelationValidationService: - output_enabled: true -``` - -[/warning] +> [!WARNING] +> Please specify a $belongs_many_many-relationship on the related class as well, in order +> to have the necessary accessors available on both ends. You can use `RelationValidationService` for validation of relationships. This tool will point out the relationships which may need a review. +> +> Example configuration: +> +> ```yml +> SilverStripe\Dev\Validation\RelationValidationService: +> output_enabled: true +> ``` Much like the `has_one` relationship, `many_many` can be navigated through the `ORM` as well. The only difference being you will get an instance of [ManyManyList](api:SilverStripe\ORM\ManyManyList) or @@ -690,10 +685,9 @@ If your object is versioned, cascade_deletes will also act as "cascade unpublish on a parent object will trigger unpublish on the child, similarly to how `owns` causes triggered publishing. See the [versioning docs](/developer_guides/model/versioning) for more information on ownership. -[alert] -Declaring cascade_deletes implies delete permissions on the listed objects. -Built-in controllers using delete operations check canDelete() on the owner, but not on the owned object. -[/alert] +> [!CAUTION] +> Declaring cascade_deletes implies delete permissions on the listed objects. +> Built-in controllers using delete operations check canDelete() on the owner, but not on the owned object. ## Cascading duplications @@ -793,10 +787,9 @@ class Team extends DataObject } ``` -[notice] -Adding new records to a filtered `RelationList` like in the example above doesn't automatically set the filtered -criteria on the added record. -[/notice] +> [!WARNING] +> Adding new records to a filtered `RelationList` like in the example above doesn't automatically set the filtered +> criteria on the added record. ## Relations on unsaved objects diff --git a/en/02_Developer_Guides/00_Model/05_Extending_DataObjects.md b/en/02_Developer_Guides/00_Model/05_Extending_DataObjects.md index d00079cf1..793a2a6b3 100644 --- a/en/02_Developer_Guides/00_Model/05_Extending_DataObjects.md +++ b/en/02_Developer_Guides/00_Model/05_Extending_DataObjects.md @@ -88,10 +88,9 @@ class Player extends DataObject } ``` -[notice] -Note: There are no separate methods for `onBeforeCreate()` and `onBeforeUpdate()`. Please check `$this->isInDb()` to toggle -these two modes, as shown in the example above. -[/notice] +> [!WARNING] +> Note: There are no separate methods for `onBeforeCreate()` and `onBeforeUpdate()`. Please check `$this->isInDb()` to toggle +> these two modes, as shown in the example above. ## Related lessons diff --git a/en/02_Developer_Guides/00_Model/07_Permissions.md b/en/02_Developer_Guides/00_Model/07_Permissions.md index e96724db1..6341efda1 100644 --- a/en/02_Developer_Guides/00_Model/07_Permissions.md +++ b/en/02_Developer_Guides/00_Model/07_Permissions.md @@ -14,10 +14,9 @@ The API provides four methods for this purpose: `canEdit()`, `canCreate()`, `can Since they're PHP methods, they can contain arbitrary logic matching your own requirements. They can optionally receive a `$member` argument, and default to the currently logged in member (through `Security::getCurrentUser()`). -[notice] -By default, all `DataObject` subclasses can only be edited, created and viewed by users with the 'ADMIN' permission -code. -[/notice] +> [!WARNING] +> By default, all `DataObject` subclasses can only be edited, created and viewed by users with the 'ADMIN' permission +> code. ```php namespace App\Model; @@ -49,11 +48,10 @@ class MyDataObject extends DataObject } ``` -[alert] -These checks are not enforced on low-level ORM operations such as `write()` or `delete()`, but rather rely on being -checked in the invoking code. The CMS default sections as well as custom interfaces like [ModelAdmin](api:SilverStripe\Admin\ModelAdmin) or -[GridField](api:SilverStripe\Forms\GridField\GridField) already enforce these permissions. -[/alert] +> [!CAUTION] +> These checks are not enforced on low-level ORM operations such as `write()` or `delete()`, but rather rely on being +> checked in the invoking code. The CMS default sections as well as custom interfaces like [ModelAdmin](api:SilverStripe\Admin\ModelAdmin) or +> [GridField](api:SilverStripe\Forms\GridField\GridField) already enforce these permissions. ## API documentation diff --git a/en/02_Developer_Guides/00_Model/08_SQL_Select.md b/en/02_Developer_Guides/00_Model/08_SQL_Select.md index 72bff5134..87c485173 100644 --- a/en/02_Developer_Guides/00_Model/08_SQL_Select.md +++ b/en/02_Developer_Guides/00_Model/08_SQL_Select.md @@ -49,10 +49,9 @@ various assumptions the ORM and code based on it have: We'll explain some ways to use `SELECT` with the full power of SQL, but still maintain a connection to the ORM where possible. -[warning] -Please read our [security topic](/developer_guides/security) to find out -how to properly prepare user input and variables for use in queries -[/warning] +> [!WARNING] +> Please read our [security topic](/developer_guides/security) to find out +> how to properly prepare user input and variables for use in queries ## Usage diff --git a/en/02_Developer_Guides/00_Model/10_Versioning.md b/en/02_Developer_Guides/00_Model/10_Versioning.md index 0a54418e5..984c50b98 100644 --- a/en/02_Developer_Guides/00_Model/10_Versioning.md +++ b/en/02_Developer_Guides/00_Model/10_Versioning.md @@ -13,20 +13,19 @@ from published content shown to your website visitors. Versioning in Silverstripe CMS is handled through the [Versioned](api:SilverStripe\Versioned\Versioned) class. As a [DataExtension](api:SilverStripe\ORM\DataExtension) it is possible to be applied to any [DataObject](api:SilverStripe\ORM\DataObject) subclass. The extension class will automatically update read and write operations done via the ORM via the `augmentSQL` database hook. -[notice] -There are two complementary modules that improve content editor experience around "owned" nested objects (e.g. elemental blocks). -Those are in experimental status right now, but we would appreciate any feedback and contributions. - -You can check them out on GitHub: - -- -- - -The first one adds extra metadata to versions about object parents at the moment of version creation. -The second module extends CMS History UI adding control over nested objects. - -![Example screenshot from versioned-snapshot-admin](../../_images/snapshot-admin.png) -[/notice] +> [!WARNING] +> There are two complementary modules that improve content editor experience around "owned" nested objects (e.g. elemental blocks). +> Those are in experimental status right now, but we would appreciate any feedback and contributions. +> +> You can check them out on GitHub: +> +> - +> - +> +> The first one adds extra metadata to versions about object parents at the moment of version creation. +> The second module extends CMS History UI adding control over nested objects. +> +> ![Example screenshot from versioned-snapshot-admin](../../_images/snapshot-admin.png) ## Understanding versioning concepts @@ -65,11 +64,10 @@ Silverstripe CMS makes this possible by using the concept of *cascade publishing A non-recursive publish operation is also available if you want to publish a new version of a object without cascade publishing all its children. -[alert] -Declaring ownership implies publish permissions on owned objects. -Built-in controllers using cascading publish operations check canPublish() -on the owner, but not on the owned object. -[/alert] +> [!CAUTION] +> Declaring ownership implies publish permissions on owned objects. +> Built-in controllers using cascading publish operations check canPublish() +> on the owner, but not on the owned object. #### Ownership of unversioned object @@ -94,11 +92,10 @@ Changes to many objects can be grouped together using the [`ChangeSet`](api:Silv Records can be added to a changeset in the CMS by using the "Add to campaign" button that is available on the edit forms of all pages and files. Programmatically, this is done by creating a `SilverStripe\Versioned\ChangeSet` object and invoking its `addObject(DataObject $record)` method. -[info] -DataObjects can be added to more than one ChangeSet. -Most of the time, these objects contain changes. -A ChangeSet can contain unchanged objects as well. -[/info] +> [!NOTE] +> DataObjects can be added to more than one ChangeSet. +> Most of the time, these objects contain changes. +> A ChangeSet can contain unchanged objects as well. #### Implicit vs. Explicit inclusions @@ -116,6 +113,10 @@ This section explains how to take a regular DataObject and add versioning to it. ### Applying the `Versioned` extension to your `DataObject` +> [!WARNING] +> Versioning only works if you are adding the extension to the base class. That is, the first subclass +> of `DataObject`. Adding this extension to children of the base class will have unpredictable behaviour. + ```php namespace App\Model; @@ -148,15 +149,9 @@ class VersionedModel extends DataObject } ``` -[notice] -The extension is automatically applied to the `SiteTree` class. For more information on extensions see -[extending](/developer_guides/extending/) and the [configuration](/developer_guides/configuration/) documentation. -[/notice] - -[warning] -Versioning only works if you are adding the extension to the base class. That is, the first subclass -of `DataObject`. Adding this extension to children of the base class will have unpredictable behaviour. -[/warning] +> [!WARNING] +> The extension is automatically applied to the `SiteTree` class. For more information on extensions see +> [extending](/developer_guides/extending/) and the [configuration](/developer_guides/configuration/) documentation. ### Defining ownership between related versioned `DataObject` models @@ -370,10 +365,9 @@ use SilverStripe\Versioned\Versioned; $historicalRecord = Versioned::get_version('MyRecord', $recordId, $versionId); ``` -[alert] -The record is retrieved as a `DataObject`, but saving back modifications via `write()` will create a new version, -rather than modifying the existing one. -[/alert] +> [!CAUTION] +> The record is retrieved as a `DataObject`, but saving back modifications via `write()` will create a new version, +> rather than modifying the existing one. In order to get a list of all versions for a specific record, we need to generate specialized [Versioned_Version](api:SilverStripe\Versioned\Versioned_Version) objects, which expose the same database information as a `DataObject`, but also include information about when and how @@ -540,10 +534,9 @@ Depending on whether staging is enabled, one or more new tables will be created is always created to track historic versions for your model. If staging is enabled this will also create a new `_Live` table once you've rebuilt the database. -[notice] -Note that the "Stage" naming has a special meaning here, it will leave the original table name unchanged, rather than -adding a suffix. -[/notice] +> [!WARNING] +> Note that the "Stage" naming has a special meaning here, it will leave the original table name unchanged, rather than +> adding a suffix. - `MyRecord` table: Contains staged data - `MyRecord_Live` table: Contains live data @@ -706,22 +699,20 @@ SilverStripe\Control\Director: 'my-objects/$ID': 'App\Control\MyObjectController' ``` -[alert] -The `choose_site_stage()` call only deals with setting the default stage, and doesn't check if the user is -authenticated to view it. As with any other controller logic, please use `DataObject->canView()` to determine -permissions, and avoid exposing unpublished content to your users. -[/alert] +> [!CAUTION] +> The `choose_site_stage()` call only deals with setting the default stage, and doesn't check if the user is +> authenticated to view it. As with any other controller logic, please use `DataObject->canView()` to determine +> permissions, and avoid exposing unpublished content to your users. ### Controlling permissions to versioned `DataObject` models By default, `Versioned` will come out of the box with security extensions which restrict the visibility of objects in Draft (stage) or Archive viewing mode. -[alert] -As is standard practice, user code should always invoke `canView()` on any object before -rendering it. DataLists do not filter on `canView()` automatically, so this must be -done via user code. This can be achieved either by wrapping `<% if $canView %>;` in -your template, or by implementing your visibility check in PHP. -[/alert] +> [!CAUTION] +> As is standard practice, user code should always invoke `canView()` on any object before +> rendering it. DataLists do not filter on `canView()` automatically, so this must be +> done via user code. This can be achieved either by wrapping `<% if $canView %>;` in +> your template, or by implementing your visibility check in PHP. #### Version specific *can* methods @@ -909,11 +900,10 @@ Since Silverstripe CMS 4.3 you can use the React and GraphQL driven history view comparisons for a versioned DataObject. This is automatically enabled for SiteTree objects and content blocks in [dnadesign/silverstripe-elemental](https://github.com/dnadesign/silverstripe-elemental). -[warning] -Because of the lack of specificity in the `HistoryViewer.Form_ItemEditForm` scope used when injecting the history viewer to the DOM, only one model can have a working history panel at a time, with exception to `SiteTree` which has its own history viewer scope. For example, if you already have `dnadesign/silverstripe-elemental` installed, the custom history viewer instance injected as a part of this documentation will *break* the one provided by the elemental module. - -There are ways you can get around this limitation. You may wish to put some conditional logic in `app/client/src/boot/index.js` below to only perform the transformations if the current location is within a specific model admin, for example. -[/warning] +> [!WARNING] +> Because of the lack of specificity in the `HistoryViewer.Form_ItemEditForm` scope used when injecting the history viewer to the DOM, only one model can have a working history panel at a time, with exception to `SiteTree` which has its own history viewer scope. For example, if you already have `dnadesign/silverstripe-elemental` installed, the custom history viewer instance injected as a part of this documentation will *break* the one provided by the elemental module. +> +> There are ways you can get around this limitation. You may wish to put some conditional logic in `app/client/src/boot/index.js` below to only perform the transformations if the current location is within a specific model admin, for example. If you want to enable the history viewer for a custom versioned DataObject, you will need to: @@ -922,11 +912,10 @@ If you want to enable the history viewer for a custom versioned DataObject, you - Register your GraphQL queries and mutations with Injector - Add a HistoryViewerField to the DataObject's `getCMSFields` -[notice] -**Please note:** these examples are given in the context of project-level customisation. You may need to adjust -the webpack configuration slightly for use in a module. They are also designed to be used on Silverstripe CMS 4.3 or -later. -[/notice] +> [!WARNING] +> **Please note:** these examples are given in the context of project-level customisation. You may need to adjust +> the webpack configuration slightly for use in a module. They are also designed to be used on Silverstripe CMS 4.3 or +> later. ### Setup {#history-viewer-setup} @@ -960,14 +949,9 @@ class MyVersionedObject extends DataObject If you haven't already configured frontend asset (JavaScript/CSS) building for your project, you will need to configure some basic packages to be built in order to enable history viewer functionality. This section includes a very basic webpack configuration which uses [@silverstripe/webpack-config](https://www.npmjs.com/package/@silverstripe/webpack-config). -[hint] -If you have this configured for your project already, ensure you have the `react-apollo` and `graphql-tag` libraries in your `package.json` -requirements (with the appropriate version constraints from below), and skip this section. -[/hint] - -[notice] -Using `@silverstripe/webpack-config` will keep your transpiled bundle size smaller and ensure you are using the correct versions of `react-apollo` and `graphql-tag`, as these will automatically be added as [webpack externals](https://webpack.js.org/configuration/externals/). If you are not using that npm package, it is very important you use the correct versions of those dependencies. -[/notice] +> [!TIP] +> If you have this configured for your project already, ensure you have the `react-apollo` and `graphql-tag` libraries in your `package.json` +> requirements (with the appropriate version constraints from below), and skip this section. You can configure your directory structure like so: @@ -993,6 +977,9 @@ You can configure your directory structure like so: } ``` +> [!WARNING] +> Using `@silverstripe/webpack-config` will keep your transpiled bundle size smaller and ensure you are using the correct versions of `react-apollo` and `graphql-tag`, as these will automatically be added as [webpack externals](https://webpack.js.org/configuration/externals/). If you are not using that npm package, it is very important you use the correct versions of those dependencies. + ```js // webpack.config.js const Path = require('path'); @@ -1033,9 +1020,8 @@ module.exports = [ At this stage, running `yarn build` should correctly build `app/client/dist/js/bundle.js`. -[notice] -Don't forget to [configure your project's "exposed" folders](/developer_guides/templates/requirements/#configuring-your-project-exposed-folders) and run `composer vendor-expose` on the command line so that the browser has access to your new dist JS file. -[/notice] +> [!WARNING] +> Don't forget to [configure your project's "exposed" folders](/developer_guides/templates/requirements/#configuring-your-project-exposed-folders) and run `composer vendor-expose` on the command line so that the browser has access to your new dist JS file. ### Create and use GraphQL schema {#history-viewer-gql} @@ -1269,77 +1255,75 @@ export { mutation, config }; export default graphql(mutation, config); ``` -[hint] -While `silverstripe/graphql` v4 ignores the namespace when generating names for types, queries, and mutations, v3 includes the first part of the namespace in each of those designations. If you're implementing this for a project that still uses `silverstripe/graphql` v3, make the following changes: - -```diff -# app/client/src/state/readOneMyVersionedObjectQuery.js - import { graphql } from 'react-apollo'; - import gql from 'graphql-tag'; - --// Note that "readOneMyVersionedObject" is the query name in the schema, while -+// Note that "readOneAppMyVersionedObject" is the query name in the schema, while - // "ReadHistoryViewerMyVersionedObject" is an arbitrary name we're using for this invocation - // of the query - const query = gql` - query ReadHistoryViewerMyVersionedObject ($id: ID!, $limit: Int!, $offset: Int!) { -- readOneMyVersionedObject( -+ readOneAppMyVersionedObject( - versioning: { - mode: ALL_VERSIONS - }, -- filter: { -- id: { eq: $id } -- } -+ id: $id - ) { - id - versions (limit: $limit, offset: $offset, sort: { - -... - - data: { - error, - refetch, -- readOneMyVersionedObject, -+ readOneAppMyVersionedObject, - loading: networkLoading, - }, - ownProps: { - -... - - recordId, - }, - }) { -- const versions = readOneMyVersionedObject || null; -+ const versions = readOneAppMyVersionedObject || null; - - const errors = error && error.graphQLErrors && - -... -``` - -```diff -# app/client/src/state/revertToMyVersionedObjectVersionMutation.js - import { graphql } from 'react-apollo'; - import gql from 'graphql-tag'; - --// Note that "rollbackMyVersionedObject" is the mutation name in the schema, while -+// Note that "rollbackAppMyVersionedObject" is the mutation name in the schema, while - // "revertToMyVersionedObject" is an arbitrary name we're using for this invocation - // of the mutation - const mutation = gql` - mutation revertToMyVersionedObject($id:ID!, $toVersion:Int!) { -- rollbackMyVersionedObject( -+ rollbackAppMyVersionedObject( - id: $id - toVersion: $toVersion - ) { -... -``` - -[/hint] +> [!TIP] +> While `silverstripe/graphql` v4 ignores the namespace when generating names for types, queries, and mutations, v3 includes the first part of the namespace in each of those designations. If you're implementing this for a project that still uses `silverstripe/graphql` v3, make the following changes: +> +> ```diff +> # app/client/src/state/readOneMyVersionedObjectQuery.js +> import { graphql } from 'react-apollo'; +> import gql from 'graphql-tag'; +> +> -// Note that "readOneMyVersionedObject" is the query name in the schema, while +> +// Note that "readOneAppMyVersionedObject" is the query name in the schema, while +> // "ReadHistoryViewerMyVersionedObject" is an arbitrary name we're using for this invocation +> // of the query +> const query = gql` +> query ReadHistoryViewerMyVersionedObject ($id: ID!, $limit: Int!, $offset: Int!) { +> - readOneMyVersionedObject( +> + readOneAppMyVersionedObject( +> versioning: { +> mode: ALL_VERSIONS +> }, +> - filter: { +> - id: { eq: $id } +> - } +> + id: $id +> ) { +> id +> versions (limit: $limit, offset: $offset, sort: { +> +> ... +> +> data: { +> error, +> refetch, +> - readOneMyVersionedObject, +> + readOneAppMyVersionedObject, +> loading: networkLoading, +> }, +> ownProps: { +> +> ... +> +> recordId, +> }, +> }) { +> - const versions = readOneMyVersionedObject || null; +> + const versions = readOneAppMyVersionedObject || null; +> +> const errors = error && error.graphQLErrors && +> +> ... +> ``` +> +> ```diff +> # app/client/src/state/revertToMyVersionedObjectVersionMutation.js +> import { graphql } from 'react-apollo'; +> import gql from 'graphql-tag'; +> +> -// Note that "rollbackMyVersionedObject" is the mutation name in the schema, while +> +// Note that "rollbackAppMyVersionedObject" is the mutation name in the schema, while +> // "revertToMyVersionedObject" is an arbitrary name we're using for this invocation +> // of the mutation +> const mutation = gql` +> mutation revertToMyVersionedObject($id:ID!, $toVersion:Int!) { +> - rollbackMyVersionedObject( +> + rollbackAppMyVersionedObject( +> id: $id +> toVersion: $toVersion +> ) { +> ... +> ``` #### Register your GraphQL query and mutation with `Injector` diff --git a/en/02_Developer_Guides/00_Model/11_Scaffolding.md b/en/02_Developer_Guides/00_Model/11_Scaffolding.md index 8f04f7daa..6b466bf70 100644 --- a/en/02_Developer_Guides/00_Model/11_Scaffolding.md +++ b/en/02_Developer_Guides/00_Model/11_Scaffolding.md @@ -73,22 +73,16 @@ class MyDataObject extends DataObject You can also alter the fields of built-in and module `DataObject` classes through your own [DataExtension](/developer_guides/extending/extensions), and a call to `DataExtension->updateCMSFields`. -[info] -`FormField` scaffolding takes [`$field_labels` config](#field-labels) into account as well. -[/info] +> [!NOTE] +> `FormField` scaffolding takes [`$field_labels` config](#field-labels) into account as well. ## Searchable fields The `$searchable_fields` property uses a mixed array format that can be used to further customise your generated admin system. The default is a set of array values listing the fields. -[info] -`$searchable_fields` will default to use the [`$summary_fields` config](#summary-fields), excluding anything that isn't a database field (such as method calls) if not explicitly defined. -[/info] - -[warning] -If you define a `searchable_fields` configuration, *do not* specify fields that are not stored in the database (such as methods), as this will cause an error. -[/warning] +> [!NOTE] +> `$searchable_fields` will default to use the [`$summary_fields` config](#summary-fields), excluding anything that isn't a database field (such as method calls) if not explicitly defined. ```php namespace App\Model; @@ -104,6 +98,9 @@ class MyDataObject extends DataObject } ``` +> [!WARNING] +> If you define a `searchable_fields` configuration, *do not* specify fields that are not stored in the database (such as methods), as this will cause an error. + ### General search field Tabular views such as `GridField` or `ModalAdmin` include a search bar. As of Silverstripe CMS 4.12, the search bar will search across all of your searchable fields by default. It will return a match if the search terms appear in any of the searchable fields. @@ -132,9 +129,8 @@ class MyDataObject extends DataObject By default the general search field uses the name "q". If you already use that field name or search query in your [SearchContext](/developer_guides/search/searchcontext), you can change this to whatever name you prefer either globally or per class: -[hint] -If you set `general_search_field_name` to any empty string, general search will be disabled entirely. Instead, the first field in your searchable fields configuration will be used, which was the default behaviour prior to Silverstripe CMS 4.12. -[/hint] +> [!TIP] +> If you set `general_search_field_name` to any empty string, general search will be disabled entirely. Instead, the first field in your searchable fields configuration will be used, which was the default behaviour prior to Silverstripe CMS 4.12. ##### Globally change the general search field name via YAML config {#general-field-name-yaml} @@ -190,9 +186,8 @@ class MyDataObject extends DataObject } ``` -[warning] -You may get unexpected results using some filters if you don't disable splitting the query into terms - for example if you use an [ExactMatchFilter](api:SilverStripe\ORM\Filters\ExactMatchFilter), each term in the query *must* exactly match the value in at least one field to get a match. If you disable splitting terms, the whole query must exactly match a field value instead. -[/warning] +> [!WARNING] +> You may get unexpected results using some filters if you don't disable splitting the query into terms - for example if you use an [ExactMatchFilter](api:SilverStripe\ORM\Filters\ExactMatchFilter), each term in the query *must* exactly match the value in at least one field to get a match. If you disable splitting terms, the whole query must exactly match a field value instead. #### Splitting search queries into individual terms @@ -384,9 +379,8 @@ class Player extends DataObject Use a single search field that matches on multiple database fields with `'match_any'`. This also supports specifying a field and a filter, though it is not necessary to do so. -[alert] -If you don't specify a field, you must use the name of a real database field instead of a custom name so that a default field can be determined. -[/alert] +> [!CAUTION] +> If you don't specify a field, you must use the name of a real database field instead of a custom name so that a default field can be determined. ```php namespace App\Model; diff --git a/en/02_Developer_Guides/00_Model/12_Indexes.md b/en/02_Developer_Guides/00_Model/12_Indexes.md index d3c4efc6f..029847760 100644 --- a/en/02_Developer_Guides/00_Model/12_Indexes.md +++ b/en/02_Developer_Guides/00_Model/12_Indexes.md @@ -79,10 +79,9 @@ class MyTestObject extends DataObject } ``` -[alert] -Please note that if you have previously used the removed `value` key to define an index's contents, Silverstripe CMS will -now throw an error. Use `columns` instead. -[/alert] +> [!CAUTION] +> Please note that if you have previously used the removed `value` key to define an index's contents, Silverstripe CMS will +> now throw an error. Use `columns` instead. ## Complex/Composite indexes diff --git a/en/02_Developer_Guides/00_Model/13_Managing_Records.md b/en/02_Developer_Guides/00_Model/13_Managing_Records.md index f84b23585..a4c08408f 100644 --- a/en/02_Developer_Guides/00_Model/13_Managing_Records.md +++ b/en/02_Developer_Guides/00_Model/13_Managing_Records.md @@ -69,10 +69,9 @@ class MyParentModel extends DataObject } ``` -[hint] -If the `cms_edit_owner` is in some vendor dependency that you don't control, you can always apply `CMSEditLinkExtension` -and the `cms_edit_owner` via YAML. -[/hint] +> [!TIP] +> If the `cms_edit_owner` is in some vendor dependency that you don't control, you can always apply `CMSEditLinkExtension` +> and the `cms_edit_owner` via YAML. With the above code examples, you can call `CMSEditLink()` on any instance of `MyModel` or `MyParentModel` and it will produce an appropriate edit link for that record (assuming the relations are set up). This can be used, for example, in email reminders @@ -81,8 +80,7 @@ to update content, or as a link (available to admins) on the front-end to go str It is also useful when [making a previewable `DataObject`](../customising_the_admin_interface/preview/), as `CMSEditLink()` is one of the methods in the [CMSPreviewable](api:SilverStripe\ORM\CMSPreviewable) interface. -[info] -`SiteTree` already has `CMSEditLinkExtension` applied, which means any `cms_edit_owner` pointing to a `has_one` relation of -a `SiteTree` will work, assuming the page has a `GridField` for its reciprocal `has_many` relation with a `GridFieldDetailForm` -in it. -[/info] +> [!NOTE] +> `SiteTree` already has `CMSEditLinkExtension` applied, which means any `cms_edit_owner` pointing to a `has_one` relation of +> a `SiteTree` will work, assuming the page has a `GridField` for its reciprocal `has_many` relation with a `GridFieldDetailForm` +> in it. diff --git a/en/02_Developer_Guides/01_Templates/01_Syntax.md b/en/02_Developer_Guides/01_Templates/01_Syntax.md index 5480c6a37..2f8c7ebce 100644 --- a/en/02_Developer_Guides/01_Templates/01_Syntax.md +++ b/en/02_Developer_Guides/01_Templates/01_Syntax.md @@ -42,10 +42,9 @@ An example of a Silverstripe CMS template is below: ``` -[note] -Templates can be used for more than HTML output. You can use them to output your data as JSON, XML, CSV or any other -text-based format. -[/note] +> [!NOTE] +> Templates can be used for more than HTML output. You can use them to output your data as JSON, XML, CSV or any other +> text-based format. ## Template file location @@ -89,18 +88,16 @@ These variables will call a method / field on the object and insert the returned - `$Foo(param)` will call `$obj->Foo("param")` - `$Foo.Bar` will call `$obj->Foo()->Bar()` +> [!WARNING] +> If you wish to pass parameters to getter functions, you must use the full method name, e.g. $getThing('param'). Also, parameters must be literals, and cannot be other template variables (`$getThing($variable)` will not work) + If a variable returns a string, that string will be inserted into the template. If the variable returns an object, then the system will attempt to render the object through its `forTemplate()` method. If the `forTemplate()` method has not been defined, the system will return an error. -[notice] -If you wish to pass parameters to getter functions, you must use the full method name, e.g. $getThing('param'). Also, parameters must be literals, and cannot be other template variables (`$getThing($variable)` will not work) -[/notice] - -[note] -For more detail around how variables are inserted and formatted into a template see -[Formatting, Modifying and Casting Variables](/developer_guides/templates/casting/) -[/note] +> [!NOTE] +> For more detail around how variables are inserted and formatted into a template see +> [Formatting, Modifying and Casting Variables](/developer_guides/templates/casting/) Variables can come from your database fields, or custom methods you define on your objects. @@ -126,9 +123,8 @@ class MyObject extends DataObject

You are coming from $UsersIpAddress.

``` -[note] -Method names that begin with `get` will automatically be resolved when their prefix is excluded. For example, the above method call `$UsersIpAddress` would also invoke a method named `getUsersIpAddress()`. -[/note] +> [!NOTE] +> Method names that begin with `get` will automatically be resolved when their prefix is excluded. For example, the above method call `$UsersIpAddress` would also invoke a method named `getUsersIpAddress()`. The variables that can be used in a template vary based on the object currently in [scope](#scope). Scope defines what object the methods get called on. For the standard `Page.ss` template the scope is the current [PageController](api:SilverStripe\CMS\Controllers\ContentController\PageController) @@ -162,9 +158,8 @@ A conditional can also check for a value other than falsy. <% end_if %> ``` -[notice] -When inside template tags variables should have a '$' prefix, and literals should have quotes. -[/notice] +> [!WARNING] +> When inside template tags variables should have a '$' prefix, and literals should have quotes. Conditionals can also provide the `else` case. @@ -291,13 +286,12 @@ collection. This snippet loops over the children of a page, and generates an unordered list showing the `Title` property from each page. -[notice] -The `$Title` inside the loop refers to the Title property on each object that is looped over, not the current page like -the reference of `$Title` outside the loop. - -This demonstrates the concept of [Scope](#scope). When inside a <% loop %> the scope of the template has changed to the -object that is being looped over. -[/notice] +> [!WARNING] +> The `$Title` inside the loop refers to the Title property on each object that is looped over, not the current page like +> the reference of `$Title` outside the loop. +> +> This demonstrates the concept of [Scope](#scope). When inside a <% loop %> the scope of the template has changed to the +> object that is being looped over. ### Altering the list @@ -383,10 +377,9 @@ iteration. ``` -[info] -A common task is to paginate your lists. See the [Pagination](how_tos/pagination) how to for a tutorial on adding -pagination. -[/info] +> [!NOTE] +> A common task is to paginate your lists. See the [Pagination](how_tos/pagination) how to for a tutorial on adding +> pagination. ### `Modulus` and `MultipleOf` @@ -408,10 +401,9 @@ $MultipleOf(factor, offset) // returns
,
, ``` -[hint] -`$Modulus` is useful for floated grid CSS layouts. If you want 3 rows across, put $Modulus(3) as a class and add a -`clear: both` to `.column-1`. -[/hint] +> [!TIP] +> `$Modulus` is useful for floated grid CSS layouts. If you want 3 rows across, put $Modulus(3) as a class and add a +> `clear: both` to `.column-1`. `$MultipleOf(value, offset)` can also be utilized to build column and grid layouts. In this case we want to add a `
` after every 3rd item. @@ -447,9 +439,8 @@ $Foo // returns "3" \$Foo // returns "$Foo" ``` -[hint] -For more information on formatting and casting variables see [Formatting, Modifying and Casting Variables](casting) -[/hint] +> [!TIP] +> For more information on formatting and casting variables see [Formatting, Modifying and Casting Variables](casting) ## Scope @@ -505,9 +496,8 @@ Given the following structure, it will output the text. Page 'Child 2' is a child of 'MyPage' ``` -[notice] -Additional selectors implicitly change the scope so you need to put additional `$Up` to get what you expect. -[/notice] +> [!WARNING] +> Additional selectors implicitly change the scope so you need to put additional `$Up` to get what you expect. ```ss

Children of '$Title'

diff --git a/en/02_Developer_Guides/01_Templates/02_Common_Variables.md b/en/02_Developer_Guides/01_Templates/02_Common_Variables.md index 123d4d5f2..b8e9c12e7 100644 --- a/en/02_Developer_Guides/01_Templates/02_Common_Variables.md +++ b/en/02_Developer_Guides/01_Templates/02_Common_Variables.md @@ -14,20 +14,18 @@ explained in more detail on the [syntax](syntax#scope) page. Many of the methods scope, and you can specify additional static methods to be available globally in templates by implementing the [TemplateGlobalProvider](api:SilverStripe\View\TemplateGlobalProvider) interface. -[notice] -Want a quick way of knowing what scope you're in? Try putting `$ClassName` in your template. You should see a string -such as `Page` of the object that's in scope. The methods you can call on that object then are any functions, database -properties or relations on the `Page` class, `PageController` class as well as anything from their subclasses **or** -extensions. -[/notice] +> [!WARNING] +> Want a quick way of knowing what scope you're in? Try putting `$ClassName` in your template. You should see a string +> such as `Page` of the object that's in scope. The methods you can call on that object then are any functions, database +> properties or relations on the `Page` class, `PageController` class as well as anything from their subclasses **or** +> extensions. Outputting these variables is only the start, if you want to format or manipulate them before adding them to the template have a read of the [Formatting, Modifying and Casting Variables](casting) documentation. -[alert] -Some of the following only apply when you have the `CMS` module installed. If you're using the `Framework` alone, this -functionality may not be included. -[/alert] +> [!CAUTION] +> Some of the following only apply when you have the `CMS` module installed. If you're using the `Framework` alone, this +> functionality may not be included. ## Base tag @@ -45,9 +43,8 @@ to locate your site’s images and CSS files. It renders in the template as `` -[alert] -A `<% base_tag %>;` is nearly always required or assumed by Silverstripe CMS to exist. -[/alert] +> [!CAUTION] +> A `<% base_tag %>;` is nearly always required or assumed by Silverstripe CMS to exist. ## `CurrentMember` @@ -72,9 +69,8 @@ Most objects within Silverstripe CMS will respond to `$Title` (i.e. they should The CMS module in particular provides two fields to label a page: `Title` and `MenuTitle`. `Title` is the title displayed on the web page, while `MenuTitle` can be a shorter version suitable for size-constrained menus. -[notice] -If `MenuTitle` is left blank by the CMS author, it'll just default to the value in `Title`. -[/notice] +> [!WARNING] +> If `MenuTitle` is left blank by the CMS author, it'll just default to the value in `Title`. ## Page content @@ -85,21 +81,19 @@ $Content It returns the database content of the `Content` property. With the CMS Module, this is the value of the WYSIWYG editor but it is also the standard for any object that has a body of content to output. -[info] -Please note that this database content can be "versioned", meaning that draft content edited in the CMS can be different -from published content shown to your website visitors. In templates, you don't need to worry about this distinction. - -The `$Content` variable contains the published content by default,and only preview draft content if explicitly -requested (e.g. by the "preview" feature in the CMS) (see the [versioning documentation](/../model/versioning) for -more details). -[/info] +> [!NOTE] +> Please note that this database content can be "versioned", meaning that draft content edited in the CMS can be different +> from published content shown to your website visitors. In templates, you don't need to worry about this distinction. +> +> The `$Content` variable contains the published content by default,and only preview draft content if explicitly +> requested (e.g. by the "preview" feature in the CMS) (see the [versioning documentation](/../model/versioning) for +> more details). ### `SiteConfig`: global settings -[notice] -`SiteConfig` is a module that is bundled with the CMS. If you wish to include `SiteConfig` in your framework only -web pages, you'll need to install it via composer. -[/notice] +> [!WARNING] +> `SiteConfig` is a module that is bundled with the CMS. If you wish to include `SiteConfig` in your framework only +> web pages, you'll need to install it via composer. ```ss $SiteConfig.Title @@ -117,9 +111,8 @@ The `$MetaTags` placeholder in a template returns a segment of HTML appropriate will set up title, keywords and description meta-tags, based on the CMS content and is editable in the 'Meta-data' tab on a per-page basis. -[notice] -If you don’t want to include the title tag use `$MetaTags(false)`. -[/notice] +> [!WARNING] +> If you don’t want to include the title tag use `$MetaTags(false)`. By default `$MetaTags` renders (assuming 4.11.0 is the current version of silverstripe/framework): @@ -285,10 +278,9 @@ behavior based on the page type used: Will loop over all Children records of the current object context. Children are pages that sit under the current page in the `CMS` or a custom list of data. This originates in the `Versioned` extension's `getChildren` method. -[alert] -For doing your website navigation most likely you'll want to use `$Menu` since its independent of the page -context. -[/alert] +> [!CAUTION] +> For doing your website navigation most likely you'll want to use `$Menu` since its independent of the page +> context. ### `ChildrenOf` @@ -324,9 +316,8 @@ preference, `AllChildren` does not filter by `ShowInMenus`. `$Menu(1)` returns the top-level menu of the website. You can also create a sub-menu using `$Menu(2)`, and so forth. -[notice] -Pages with the `ShowInMenus` property set to `false` will be filtered out. -[/notice] +> [!WARNING] +> Pages with the `ShowInMenus` property set to `false` will be filtered out. ## Access to a specific page @@ -396,11 +387,10 @@ of the `silverstripe/cms` module. <% end_if %> ``` -[info] -To customise the markup that `$Breadcrumbs` generates, copy `templates/BreadcrumbsTemplate.ss` - from the `silverstripe/cms` module to your theme (e.g: `themes/you-theme/templates/BreadcrumbsTemplate.ss`). - Modify the newly copied template and flush your Silverstripe CMS cache. -[/info] +> [!NOTE] +> To customise the markup that `$Breadcrumbs` generates, copy `templates/BreadcrumbsTemplate.ss` +> from the `silverstripe/cms` module to your theme (e.g: `themes/you-theme/templates/BreadcrumbsTemplate.ss`). +> Modify the newly copied template and flush your Silverstripe CMS cache. ## Forms diff --git a/en/02_Developer_Guides/01_Templates/03_Requirements.md b/en/02_Developer_Guides/01_Templates/03_Requirements.md index 2da80154b..a209a6e93 100644 --- a/en/02_Developer_Guides/01_Templates/03_Requirements.md +++ b/en/02_Developer_Guides/01_Templates/03_Requirements.md @@ -90,9 +90,8 @@ When rendered in HTML code, these URLs will be rewritten to their matching path <% require javascript("/javascript/some_file.js") %> ``` -[alert] -Requiring assets from the template is restricted compared to the PHP API. -[/alert] +> [!CAUTION] +> Requiring assets from the template is restricted compared to the PHP API. ## PHP requirements API @@ -226,10 +225,9 @@ Requirements::combine_files( ); ``` -[alert] -To make debugging easier in your local environment, combined files is disabled when running your application in `dev` -mode. You can re-enable dev combination by setting `Requirements_Backend.combine_in_dev` to true. -[/alert] +> [!CAUTION] +> To make debugging easier in your local environment, combined files is disabled when running your application in `dev` +> mode. You can re-enable dev combination by setting `Requirements_Backend.combine_in_dev` to true. ### Configuring combined file storage @@ -332,10 +330,9 @@ Requirements::combine_files('print.css', $printStylesheets, 'print'); By default, all requirements files are flushed (deleted) when ?flush querystring parameter is set. This can be disabled by setting the `Requirements.disable_flush_combined` config to `true`. -[alert] -When combining CSS files, take care of relative urls, as these will not be re-written to match -the destination location of the resulting combined CSS. -[/alert] +> [!CAUTION] +> When combining CSS files, take care of relative urls, as these will not be re-written to match +> the destination location of the resulting combined CSS. ### Combined JS files @@ -397,10 +394,9 @@ SilverStripe\Core\Injector\Injector: Minifier: '%$App\MyMinifier' ``` -[alert] -While the framework does afford you the option of minification at runtime, we recommend using one of many frontend build -tools to do this for you, e.g. [Webpack](https://webpack.github.io/), [Gulp](http://gulpjs.com/), or [Grunt](https://gruntjs.com/). -[/alert] +> [!CAUTION] +> While the framework does afford you the option of minification at runtime, we recommend using one of many frontend build +> tools to do this for you, e.g. [Webpack](https://webpack.github.io/), [Gulp](http://gulpjs.com/), or [Grunt](https://gruntjs.com/). ## Clearing assets @@ -418,9 +414,8 @@ use SilverStripe\View\Requirements; Requirements::clear('modulename/javascript/some-lib.js'); ``` -[alert] -Depending on where you call this command, a Requirement might be *re-included* afterwards. -[/alert] +> [!CAUTION] +> Depending on where you call this command, a Requirement might be *re-included* afterwards. ## Blocking @@ -437,20 +432,18 @@ use SilverStripe\View\Requirements; Requirements::block('silverstripe/admin:thirdparty/jquery/jquery.js'); ``` -[alert] -The CMS also uses the `Requirements` system, and its operation can be affected by `block()` calls. Avoid this by -limiting the scope of your blocking operations, e.g. in `init()` of your controller. -[/alert] +> [!CAUTION] +> The CMS also uses the `Requirements` system, and its operation can be affected by `block()` calls. Avoid this by +> limiting the scope of your blocking operations, e.g. in `init()` of your controller. ## Inclusion order Requirements acts like a stack, where everything is rendered sequentially in the order it was included. There is no way to change inclusion-order, other than using *Requirements::clear* and rebuilding the whole set of requirements. -[alert] -Inclusion order is both relevant for CSS and JavaScript files in terms of dependencies, inheritance and overlays - be -careful when messing with the order of requirements. -[/alert] +> [!CAUTION] +> Inclusion order is both relevant for CSS and JavaScript files in terms of dependencies, inheritance and overlays - be +> careful when messing with the order of requirements. ## JavaScript placement diff --git a/en/02_Developer_Guides/01_Templates/04_Rendering_Templates.md b/en/02_Developer_Guides/01_Templates/04_Rendering_Templates.md index 535534fc0..8117eb33a 100644 --- a/en/02_Developer_Guides/01_Templates/04_Rendering_Templates.md +++ b/en/02_Developer_Guides/01_Templates/04_Rendering_Templates.md @@ -67,10 +67,9 @@ class MyModel extends DataObject } ``` -[info] -Most classes in Silverstripe CMS you want in your template extend `ViewableData` and allow you to call `renderWith`. This -includes [Controller](api:SilverStripe\Control\Controller), [FormField](api:SilverStripe\Forms\FormField) and [DataObject](api:SilverStripe\ORM\DataObject) instances. -[/info] +> [!NOTE] +> Most classes in Silverstripe CMS you want in your template extend `ViewableData` and allow you to call `renderWith`. This +> includes [Controller](api:SilverStripe\Control\Controller), [FormField](api:SilverStripe\Forms\FormField) and [DataObject](api:SilverStripe\ORM\DataObject) instances. ```php use SilverStripe\Security\Security; diff --git a/en/02_Developer_Guides/01_Templates/06_Themes.md b/en/02_Developer_Guides/01_Templates/06_Themes.md index aff23be38..224430bc7 100644 --- a/en/02_Developer_Guides/01_Templates/06_Themes.md +++ b/en/02_Developer_Guides/01_Templates/06_Themes.md @@ -25,10 +25,9 @@ composer require my_vendor/my_theme [version] *Note:* `[version]` should be replaced with a version constraint if you know it, otherwise leave it blank to pull the latest version compatible with your project. -[alert] -As you've added new files to your Silverstripe CMS installation, make sure you clear the Silverstripe CMS cache by appending -`?flush=1` to your website URL (e.g. ). -[/alert] +> [!CAUTION] +> As you've added new files to your Silverstripe CMS installation, make sure you clear the Silverstripe CMS cache by appending +> `?flush=1` to your website URL (e.g. ). ### Configuring themes diff --git a/en/02_Developer_Guides/01_Templates/09_Casting.md b/en/02_Developer_Guides/01_Templates/09_Casting.md index d95c1e4f0..56dc1ed8d 100644 --- a/en/02_Developer_Guides/01_Templates/09_Casting.md +++ b/en/02_Developer_Guides/01_Templates/09_Casting.md @@ -36,10 +36,9 @@ $Content.FirstParagraph.NoHTML ``` -[notice] -See the API documentation for [DBHtmlText](api:SilverStripe\ORM\FieldType\DBHtmlText), [FieldType](api:SilverStripe\ORM\FieldType), [DBText](api:SilverStripe\ORM\FieldType\DBText) for all the methods you can use to format -your text instances. For other objects such as [DBDatetime](api:SilverStripe\ORM\FieldType\DBDatetime) objects see their respective API documentation pages. -[/notice] +> [!WARNING] +> See the API documentation for [DBHtmlText](api:SilverStripe\ORM\FieldType\DBHtmlText), [FieldType](api:SilverStripe\ORM\FieldType), [DBText](api:SilverStripe\ORM\FieldType\DBText) for all the methods you can use to format +> your text instances. For other objects such as [DBDatetime](api:SilverStripe\ORM\FieldType\DBDatetime) objects see their respective API documentation pages. ## ForTemplate @@ -94,10 +93,9 @@ class MyDataObject extends DataObject When calling `$Header` Silverstripe CMS now has the context that this method will contain HTML and escape the data accordingly. -[note] -By default, all content without a type explicitly defined in a `$casting` array will be assumed to be `Text` content -and HTML characters encoded. -[/note] +> [!NOTE] +> By default, all content without a type explicitly defined in a `$casting` array will be assumed to be `Text` content +> and HTML characters encoded. ## Escaping @@ -105,9 +103,8 @@ Properties are usually auto-escaped in templates to ensure consistent representa displaying un-escaped ampersands in HTML. By default, values are escaped as `XML`, which is equivalent to `HTML` for this purpose. -[note] -There's some exceptions to this rule, see the ["security" guide](../security). -[/note] +> [!NOTE] +> There's some exceptions to this rule, see the ["security" guide](../security). For every field used in templates, a casting helper will be applied. This will first check for any `casting` helper on your model specific to that field, and will fall back to the `default_cast` config @@ -150,11 +147,10 @@ See [DBField](api:SilverStripe\ORM\FieldType\DBField) for the specific implement e.g. `$Field.CDATA` will ensure that the `` body is safely escaped as a string. -[warning] -Note: Take care when using `.XML` on `HTMLText` fields, as this will result in double-encoded -html. To ensure that the correct encoding is used for that field in a template, simply use -`$Field` by itself to allow the casting helper to determine the best encoding itself. -[/warning] +> [!WARNING] +> Note: Take care when using `.XML` on `HTMLText` fields, as this will result in double-encoded +> html. To ensure that the correct encoding is used for that field in a template, simply use +> `$Field` by itself to allow the casting helper to determine the best encoding itself. ## Cast summary methods diff --git a/en/02_Developer_Guides/01_Templates/11_Partial_Template_Caching.md b/en/02_Developer_Guides/01_Templates/11_Partial_Template_Caching.md index 5940091c6..8e4322d48 100644 --- a/en/02_Developer_Guides/01_Templates/11_Partial_Template_Caching.md +++ b/en/02_Developer_Guides/01_Templates/11_Partial_Template_Caching.md @@ -19,9 +19,8 @@ is fetched from a [cache backend](../performance/caching), instead of being rege This is not a definitive example of the syntax, but it shows the most common use case. -[note] -See also [complete syntax definition](#complete-syntax-definition). -[/note] +> [!NOTE] +> See also [complete syntax definition](#complete-syntax-definition). The key parts are `$CacheKey`, `$CacheCondition` and `$CacheableContent`. The following sections explain every one of them in more detail. @@ -30,9 +29,8 @@ The following sections explain every one of them in more detail. Defines a unique key for the cache storage. -[warning] -Avoid heavy computations in `$CacheKey` as it is evaluated for every template render. -[/warning] +> [!WARNING] +> Avoid heavy computations in `$CacheKey` as it is evaluated for every template render. The formal definition is @@ -90,8 +88,6 @@ Here is how it works in detail: Even if `$CacheKey` is omitted, `SilverStripe\View\SSViewer::$global_key` and `Block hash` values are still getting used to generate cache key for the caching backend storage. -[note] - #### Cache key calculated in controller If your caching logic is complex or re-usable, you can define a method on your controller to generate a cache key @@ -130,8 +126,6 @@ Then reference that function in the cache key: <% cached $SliderCacheKey if ... %> ``` -[/note] - ### $CacheCondition Defines if caching is required for the block. @@ -152,9 +146,8 @@ Without it: - your cache backend will always be queried for cache (for every template render) - your cache backend may be cluttered with redundant and useless data -[warning] -The `$CacheCondition` value is evaluated on every template render and should be as lightweight as possible. -[/warning] +> [!WARNING] +> The `$CacheCondition` value is evaluated on every template render and should be as lightweight as possible. ### $CacheableContent @@ -168,11 +161,10 @@ By default, it is initialised by `SilverStripe\Core\Cache\DefaultCacheFactory` w - `namespace: "cacheblock"` - `defaultLifetime: 600` -[note] -The defaultLifetime 600 means every cache record expires in 10 minutes. -If you have good `$CacheKey` and `$CacheCondition` implementations, you may want to tune these settings to -improve performance. -[/note] +> [!NOTE] +> The defaultLifetime 600 means every cache record expires in 10 minutes. +> If you have good `$CacheKey` and `$CacheCondition` implementations, you may want to tune these settings to +> improve performance. Example below shows how to set partial cache expiry to one hour. @@ -215,9 +207,8 @@ The template processor will transparently flatten the structure into something s <% cached $PageKey %><% end_cached %> ``` -[note] -`$PageKey` is used twice, but evaluated only once per render because of [template object caching](caching/#object-caching). -[/note] +> [!NOTE] +> `$PageKey` is used twice, but evaluated only once per render because of [template object caching](caching/#object-caching). ## Uncached @@ -233,45 +224,42 @@ The tag `<% uncached %> ... <% end_uncached %>` disables caching for its content Because of the nested block flattening (see above), it works seamlessly on any level of depth. -[warning] -The `uncached` block only works on the lexical level. -If you have a template that caches content rendering another template with included uncached blocks, -those will not have any effect on the parent template caching blocks. -[/warning] +> [!WARNING] +> The `uncached` block only works on the lexical level. +> If you have a template that caches content rendering another template with included uncached blocks, +> those will not have any effect on the parent template caching blocks. ## Nesting in LOOP and IF blocks Currently, a cache block cannot be included in `if` and `loop` blocks. The template engine will throw an error letting you know if you've done this. -[note] -You may often get around this using aggregates or by un-nesting the block. - -For example: - -```ss -<% cached $LastEdited %> - <% loop $Children %> - <% cached $LastEdited %> - $Name - <% end_cached %> - <% end_loop %> -<% end_cached %> -``` - -Might be re-written as something like that: - -```ss -<% cached $LastEdited %> - <% cached $AllChildren.max('LastEdited') %> - <% loop $Children %> - $Name - <% end_loop %> - <% end_cached %> -<% end_cached %> -``` - -[/note] +> [!NOTE] +> You may often get around this using aggregates or by un-nesting the block. +> +> For example: +> +> ```ss +> <% cached $LastEdited %> +> <% loop $Children %> +> <% cached $LastEdited %> +> $Name +> <% end_cached %> +> <% end_loop %> +> <% end_cached %> +> ``` +> +> Might be re-written as something like that: +> +> ```ss +> <% cached $LastEdited %> +> <% cached $AllChildren.max('LastEdited') %> +> <% loop $Children %> +> $Name +> <% end_loop %> +> <% end_cached %> +> <% end_cached %> +> ``` ## Unless (syntax sugar) diff --git a/en/02_Developer_Guides/01_Templates/How_Tos/02_Pagination.md b/en/02_Developer_Guides/01_Templates/How_Tos/02_Pagination.md index eb6227d94..f7664b2f6 100644 --- a/en/02_Developer_Guides/01_Templates/How_Tos/02_Pagination.md +++ b/en/02_Developer_Guides/01_Templates/How_Tos/02_Pagination.md @@ -35,10 +35,9 @@ class MyPageController extends PageController } ``` -[notice] -Note that the concept of "pages" used in pagination does not necessarily mean that we're dealing with `Page` classes, -it's just a term to describe a sub-collection of the list. -[/notice] +> [!WARNING] +> Note that the concept of "pages" used in pagination does not necessarily mean that we're dealing with `Page` classes, +> it's just a term to describe a sub-collection of the list. There are two ways to generate pagination controls: [PaginatedList::Pages()](api:SilverStripe\ORM\PaginatedList::Pages()) and [PaginatedList::PaginationSummary()](api:SilverStripe\ORM\PaginatedList::PaginationSummary()). In this example we will use `PaginationSummary()`. diff --git a/en/02_Developer_Guides/02_Controllers/01_Introduction.md b/en/02_Developer_Guides/02_Controllers/01_Introduction.md index 6209211f6..9651ee61f 100644 --- a/en/02_Developer_Guides/02_Controllers/01_Introduction.md +++ b/en/02_Developer_Guides/02_Controllers/01_Introduction.md @@ -39,15 +39,10 @@ class TeamController extends Controller We need to define the URL that this controller can be accessed on. In our case, the `TeamsController` should be visible at and the `players` custom action is at . -[info] -If you're using the `cms` module with and dealing with `Page` objects then for your custom `Page Type` controllers you -would extend `ContentController` or `PageController`. You don't need to define the routes value as the `cms` handles -routing. -[/info] - -[alert] -Make sure that after you have modified the `routes.yml` file, that you clear your Silverstripe CMS caches using `?flush=1`. -[/alert] +> [!NOTE] +> If you're using the `cms` module with and dealing with `Page` objects then for your custom `Page Type` controllers you +> would extend `ContentController` or `PageController`. You don't need to define the routes value as the `cms` handles +> routing. ```yml # app/_config/routes.yml @@ -60,6 +55,9 @@ SilverStripe\Control\Director: 'teams//$Action/$ID/$Name': 'App\Control\TeamController' ``` +> [!CAUTION] +> Make sure that after you have modified the `routes.yml` file, that you clear your Silverstripe CMS caches using `?flush=1`. + For more information about creating custom routes, see the [Routing](routing) documentation. ## Actions @@ -67,9 +65,8 @@ For more information about creating custom routes, see the [Routing](routing) do Controllers respond by default to an `index` method. You don't need to define this method (as it's assumed) but you can override the `index()` response to provide custom data back to the [Template and Views](../templates). -[notice] -It is standard in Silverstripe CMS for your controller actions to be `lowercasewithnospaces` -[/notice] +> [!WARNING] +> It is standard in Silverstripe CMS for your controller actions to be `lowercasewithnospaces` Action methods can return one of four main things: diff --git a/en/02_Developer_Guides/02_Controllers/02_Routing.md b/en/02_Developer_Guides/02_Controllers/02_Routing.md index 3bd590f2e..56a5ad64f 100644 --- a/en/02_Developer_Guides/02_Controllers/02_Routing.md +++ b/en/02_Developer_Guides/02_Controllers/02_Routing.md @@ -8,11 +8,10 @@ summary: A more in depth look at how to map requests to particular controllers a Routing is the process of mapping URL's to [Controller](api:SilverStripe\Control\Controller) and actions. In the introduction we defined a new custom route for our `TeamController` mapping any `teams` URL to our `TeamController` -[info] -If you're using the `cms` module with and dealing with `Page` objects then for your custom `Page Type` controllers you -would extend `ContentController` or `PageController`. You don't need to define the routes value as the `cms` handles -routing. -[/info] +> [!NOTE] +> If you're using the `cms` module with and dealing with `Page` objects then for your custom `Page Type` controllers you +> would extend `ContentController` or `PageController`. You don't need to define the routes value as the `cms` handles +> routing. These routes by standard, go into a `routes.yml` file in your applications `_config` folder alongside your other [Configuration](../configuration) information. @@ -32,9 +31,8 @@ SilverStripe\Control\Director: '': 'App\Control\HomeController' ``` -[notice] -To understand the syntax for the `routes.yml` file better, read the [Configuration](../configuration) documentation. -[/notice] +> [!WARNING] +> To understand the syntax for the `routes.yml` file better, read the [Configuration](../configuration) documentation. ## Parameters @@ -50,9 +48,8 @@ It also contains 3 `parameters` or `params` for short. `$Action`, `$ID` and `$Na which will be filled when the user makes their request. Request parameters are available on the `HTTPRequest` object and able to be pulled out from a controller using `$this->getRequest()->param($name)`. -[info] -All Controllers have access to `$this->getRequest()` for the request object and `$this->getResponse()` for the response. -[/info] +> [!NOTE] +> All Controllers have access to `$this->getRequest()` for the request object and `$this->getResponse()` for the response. Here is what those parameters would look like for certain requests @@ -105,9 +102,8 @@ echo $this->getRequest()->param('ID'); The [RequestHandler](api:SilverStripe\Control\RequestHandler) class will parse all rules you specify against the following patterns. The most specific rule will be the one followed for the response. -[alert] -A rule must always start with alphabetical ([A-Za-z]) characters or a $Variable declaration -[/alert] +> [!CAUTION] +> A rule must always start with alphabetical ([A-Za-z]) characters or a $Variable declaration | Pattern | Description | | ----------- | --------------- | @@ -199,13 +195,12 @@ class StaffController extends Controller ## URL handlers -[alert] -You **must** use the **$url_handlers** static array described here if your URL -pattern does not use the Controller class's default pattern of -`$Action//$ID/$OtherID`. If you fail to do so, and your pattern has more than -2 parameters, your controller will throw the error "I can't handle sub-URLs of -a *class name* object" with HTTP status 404. -[/alert] +> [!CAUTION] +> You **must** use the **$url_handlers** static array described here if your URL +> pattern does not use the Controller class's default pattern of +> `$Action//$ID/$OtherID`. If you fail to do so, and your pattern has more than +> 2 parameters, your controller will throw the error "I can't handle sub-URLs of +> a *class name* object" with HTTP status 404. In the above example the URLs were configured using the [Director](api:SilverStripe\Control\Director) rules in the **routes.yml** file. Alternatively you can specify these in your Controller class via the **$url_handlers** static array. This array is processed by the @@ -299,9 +294,8 @@ class BreadAPIController extends Controller } ``` -[alert] -In Silverstripe CMS versions prior to 4.6, an empty key (`''`) must be used in place of the `'/'` key. When specifying an HTTP method, the empty string must be separated from the method (e.g. `'GET '`). The empty key and slash key are also equivalent in Director rules. -[/alert] +> [!CAUTION] +> In Silverstripe CMS versions prior to 4.6, an empty key (`''`) must be used in place of the `'/'` key. When specifying an HTTP method, the empty string must be separated from the method (e.g. `'GET '`). The empty key and slash key are also equivalent in Director rules. ## Nested request handlers diff --git a/en/02_Developer_Guides/02_Controllers/03_Access_Control.md b/en/02_Developer_Guides/02_Controllers/03_Access_Control.md index 151d1675b..bd974f9da 100644 --- a/en/02_Developer_Guides/02_Controllers/03_Access_Control.md +++ b/en/02_Developer_Guides/02_Controllers/03_Access_Control.md @@ -45,9 +45,8 @@ class MyController extends Controller } ``` -[info] -If the permission check fails, Silverstripe CMS will return a `403` Forbidden HTTP status. -[/info] +> [!NOTE] +> If the permission check fails, Silverstripe CMS will return a `403` Forbidden HTTP status. An action named "index" is white listed by default, unless `allowed_actions` is defined as an empty array, or the action is specifically restricted. @@ -149,9 +148,8 @@ class MyChildController extends MyController } ``` -[notice] -Access checks on parent classes need to be overwritten via the [Configuration API](../configuration). -[/notice] +> [!WARNING] +> Access checks on parent classes need to be overwritten via the [Configuration API](../configuration). ## Forms @@ -210,10 +208,9 @@ class MyController extends Controller } ``` -[notice] -This is recommended as an addition for `$allowed_actions`, in order to handle more complex checks, rather than a -replacement. -[/notice] +> [!WARNING] +> This is recommended as an addition for `$allowed_actions`, in order to handle more complex checks, rather than a +> replacement. ## Controller level checks @@ -221,9 +218,8 @@ After checking for allowed_actions, each controller invokes its `init()` method, common state, If an `init()` method returns a `HTTPResponse` with either a 3xx or 4xx HTTP status code, it'll abort execution. This behavior can be used to implement permission checks. -[info] -`init` is called for any possible action on the controller and before any specific method such as `index`. -[/info] +> [!NOTE] +> `init` is called for any possible action on the controller and before any specific method such as `index`. ```php namespace App\Control; diff --git a/en/02_Developer_Guides/02_Controllers/05_Middlewares.md b/en/02_Developer_Guides/02_Controllers/05_Middlewares.md index a3d0bd6dc..3aeddad5a 100644 --- a/en/02_Developer_Guides/02_Controllers/05_Middlewares.md +++ b/en/02_Developer_Guides/02_Controllers/05_Middlewares.md @@ -8,9 +8,8 @@ summary: Create objects for modifying request and response objects across contro HTTP Middlewares allow you to add code that will run before or after a request has been delegated to the router. These might be used for authentication, logging, caching, request processing, and many other purposes. -[notice] -Note this interface replaces the Silverstripe CMS 3 interface [RequestFilter](api:SilverStripe\Control\RequestFilter), which still works but is deprecated. -[/notice] +> [!WARNING] +> Note this interface replaces the Silverstripe CMS 3 interface [RequestFilter](api:SilverStripe\Control\RequestFilter), which still works but is deprecated. To create a middleware class, implement `SilverStripe\Control\Middleware\HTTPMiddleware` and define the `process(HTTPRequest $request, callable $delegate)` method. You can do anything you like in this diff --git a/en/02_Developer_Guides/03_Forms/00_Introduction.md b/en/02_Developer_Guides/03_Forms/00_Introduction.md index 550726092..6049b76f3 100644 --- a/en/02_Developer_Guides/03_Forms/00_Introduction.md +++ b/en/02_Developer_Guides/03_Forms/00_Introduction.md @@ -9,9 +9,8 @@ iconBrand: wpforms The HTML `Form` is the most used way to interact with a user. Silverstripe CMS provides classes to generate forms through the [Form](api:SilverStripe\Forms\Form) class, [FormField](api:SilverStripe\Forms\FormField) instances to capture data and submissions through [FormAction](api:SilverStripe\Forms\FormAction). -[notice] -See the [Introduction to frontend forms](https://www.silverstripe.org/learn/lessons/v4/introduction-to-frontend-forms-1) lesson for a step by step process of creating a `Form` -[/notice] +> [!WARNING] +> See the [Introduction to frontend forms](https://www.silverstripe.org/learn/lessons/v4/introduction-to-frontend-forms-1) lesson for a step by step process of creating a `Form` ## Creating a form @@ -88,11 +87,10 @@ class MyFormPageController extends PageController $HelloForm ``` -[info] -The examples above use `FormField::create()` instead of the `new` operator (`new FormField()`). These are functionally -equivalent, but allows PHP to chain operations like `setTitle()` without assigning the field instance to a temporary -variable. -[/info] +> [!NOTE] +> The examples above use `FormField::create()` instead of the `new` operator (`new FormField()`). These are functionally +> equivalent, but allows PHP to chain operations like `setTitle()` without assigning the field instance to a temporary +> variable. When constructing the `Form` instance (`new Form($controller, $name)`) both controller and name are required. The `$controller` and `$name` are used to allow Silverstripe CMS to calculate the origin of the `Form object`. When a user @@ -127,10 +125,9 @@ class MyFormPageController extends PageController See [routing documentation](/developer_guides/controllers/routing/) for more information about `$allowed_actions` and `$url_handlers`. -[notice] -Form actions (`doSayHello`), on the other hand, should *not* be included in `$allowed_actions`; these are handled -separately through [Form::httpSubmission()](api:SilverStripe\Forms\Form::httpSubmission()). -[/notice] +> [!WARNING] +> Form actions (`doSayHello`), on the other hand, should *not* be included in `$allowed_actions`; these are handled +> separately through [Form::httpSubmission()](api:SilverStripe\Forms\Form::httpSubmission()). ## Adding formFields @@ -143,9 +140,8 @@ use SilverStripe\Forms\TextField; TextField::create($name, $title, $value); ``` -[info] -A list of the common FormField subclasses is available on the [Common Subclasses](field_types/common_subclasses/) page. -[/info] +> [!NOTE] +> A list of the common FormField subclasses is available on the [Common Subclasses](field_types/common_subclasses/) page. The fields are added to the [FieldList](api:SilverStripe\Forms\FieldList) `fields` property on the `Form` and can be modified at up to the point the `Form` is rendered. @@ -205,20 +201,18 @@ Fields can be removed from the form. $form->getFields()->removeByName('Email'); ``` -[alert] -Forms can be tabbed (such as the CMS interface). In these cases, there are additional functions such as `addFieldToTab` -and `removeFieldByTab` to ensure the fields are on the correct interface. See [Tabbed Forms](tabbed_forms) for more -information on the CMS interface. -[/alert] +> [!CAUTION] +> Forms can be tabbed (such as the CMS interface). In these cases, there are additional functions such as `addFieldToTab` +> and `removeFieldByTab` to ensure the fields are on the correct interface. See [Tabbed Forms](tabbed_forms) for more +> information on the CMS interface. ## Modifying formFields Each [FormField](api:SilverStripe\Forms\FormField) subclass has a number of methods you can call on it to customise its' behavior or HTML markup. The default `FormField` object has several methods for doing common operations. -[notice] -Most of the `set` operations will return the object back so methods can be chained. -[/notice] +> [!WARNING] +> Most of the `set` operations will return the object back so methods can be chained. ```php use SilverStripe\Forms\TextField; @@ -344,10 +338,9 @@ with the particular button. In the previous example, clicking the 'Another Butto - The `Form` instance. - The `Controller` instance. -[notice] -If the `$action` method cannot be found on any of those or is marked as `private` or `protected`, an error will be -thrown. -[/notice] +> [!WARNING] +> If the `$action` method cannot be found on any of those or is marked as `private` or `protected`, an error will be +> thrown. The `$action` method takes two arguments: diff --git a/en/02_Developer_Guides/03_Forms/01_Validation.md b/en/02_Developer_Guides/03_Forms/01_Validation.md index 000d549c7..6eab290ef 100644 --- a/en/02_Developer_Guides/03_Forms/01_Validation.md +++ b/en/02_Developer_Guides/03_Forms/01_Validation.md @@ -65,11 +65,10 @@ class MyFormPageController extends PageController In this example we will be required to input a value for `Name` and a valid email address for `Email` before the `doSubmitForm` method is called. -[info] -Each individual [FormField](api:SilverStripe\Forms\FormField) instance is responsible for validating the submitted content through the -[FormField::validate()](api:SilverStripe\Forms\FormField::validate()) method. By default, this just checks the value exists. Fields like `EmailField` override -`validate` to check for a specific format. -[/info] +> [!NOTE] +> Each individual [FormField](api:SilverStripe\Forms\FormField) instance is responsible for validating the submitted content through the +> [FormField::validate()](api:SilverStripe\Forms\FormField::validate()) method. By default, this just checks the value exists. Fields like `EmailField` override +> `validate` to check for a specific format. Subclasses of `FormField` can define their own version of `validate` to provide custom validation rules such as the above example with the `Email` validation. The `validate` method on `FormField` takes a single argument of the current @@ -97,9 +96,8 @@ class CustomNumberField extends NumericField The `validate` method should return `true` if the value passes any validation and `false` if Silverstripe CMS should trigger a validation error on the page. In addition a useful error message must be set on the given validator. -[notice] -You can also override the entire `Form` validation by subclassing `Form` and defining a `validate` method on the form. -[/notice] +> [!WARNING] +> You can also override the entire `Form` validation by subclassing `Form` and defining a `validate` method on the form. Say we need a custom `FormField` which requires the user input a value in a `NumericField` between 2 and 5. There would be two ways to go about this: @@ -355,9 +353,8 @@ call `setValidator` easily. However, a `DataObject` can provide its own `Validat [ModelAdmin](api:SilverStripe\Admin\ModelAdmin) and [GridField](api:SilverStripe\Forms\GridField\GridField) will respect the provided `Validator`/s and handle displaying error and success responses to the user. -[info] -Again, custom error messages can be provided through the `FormField` -[/info] +> [!NOTE] +> Again, custom error messages can be provided through the `FormField` ```php namespace App\PageType; diff --git a/en/02_Developer_Guides/03_Forms/03_Form_Templates.md b/en/02_Developer_Guides/03_Forms/03_Form_Templates.md index 0feda10fd..cf645baf4 100644 --- a/en/02_Developer_Guides/03_Forms/03_Form_Templates.md +++ b/en/02_Developer_Guides/03_Forms/03_Form_Templates.md @@ -20,22 +20,20 @@ $field->setTemplate('MyCustomTextField'); To override the template for CMS forms, the custom templates should be located in `app/templates/`. Front-end form templates can be located in `app/templates/` or in the active theme's `templates/` directory. -[notice] -It's recommended to copy the contents of the template you're going to replace and use that as a start. For instance, if -you want to create a `MyCustomFormTemplate` copy the contents of `Form.ss` to a `MyCustomFormTemplate.ss` file and -modify as you need. - -*The default `Form.ss` can be found in `vendor/silverstripe/framework/templates/SilverStripe/Forms/Includes/`* -[/notice] +> [!WARNING] +> It's recommended to copy the contents of the template you're going to replace and use that as a start. For instance, if +> you want to create a `MyCustomFormTemplate` copy the contents of `Form.ss` to a `MyCustomFormTemplate.ss` file and +> modify as you need. +> +> *The default `Form.ss` can be found in `vendor/silverstripe/framework/templates/SilverStripe/Forms/Includes/`* By default, Form and Fields follow the Silverstripe CMS template convention and are rendered into templates of the same class name (i.e. `EmailField` will attempt to render into `EmailField.ss` and if that isn't found, `TextField.ss` or finally `FormField.ss`). -[alert] -While you can override all templates using normal view inheritance (i.e. defining a `Form.ss`) other modules may rely on -the core template structure. It is recommended to use `setTemplate()` and unique templates for specific forms. -[/alert] +> [!CAUTION] +> While you can override all templates using normal view inheritance (i.e. defining a `Form.ss`) other modules may rely on +> the core template structure. It is recommended to use `setTemplate()` and unique templates for specific forms. For [`FormField`](api:SilverStripe\Forms\FormField) instances, there are several other templates that are used on top of the main `setTemplate()`. diff --git a/en/02_Developer_Guides/03_Forms/04_Form_Security.md b/en/02_Developer_Guides/03_Forms/04_Form_Security.md index c3d47ef79..a14e6332d 100644 --- a/en/02_Developer_Guides/03_Forms/04_Form_Security.md +++ b/en/02_Developer_Guides/03_Forms/04_Form_Security.md @@ -16,10 +16,9 @@ Silverstripe CMS protect users against [Cross-Site Request Forgery]( -website. -[/info] +> [!NOTE] +> For more information on Cross-Site Request Forgery, consult the [OWASP]( +> website. The `SecurityToken` automatically added looks something like: @@ -48,10 +47,9 @@ $form = new Form(/* ... */); $form->disableSecurityToken(); ``` -[alert] -Do not disable the SecurityID for forms that perform some modification to the users session. This will open your -application up to `CSRF` security holes. -[/alert] +> [!CAUTION] +> Do not disable the SecurityID for forms that perform some modification to the users session. This will open your +> application up to `CSRF` security holes. ## Strict form submission diff --git a/en/02_Developer_Guides/03_Forms/06_Tabbed_Forms.md b/en/02_Developer_Guides/03_Forms/06_Tabbed_Forms.md index 303a8b59e..219a42e20 100644 --- a/en/02_Developer_Guides/03_Forms/06_Tabbed_Forms.md +++ b/en/02_Developer_Guides/03_Forms/06_Tabbed_Forms.md @@ -9,17 +9,15 @@ Silverstripe CMS's [FormScaffolder](api:SilverStripe\Forms\FormScaffolder) can a CMS and other scaffolded interfaces, it will output [TabSet](api:SilverStripe\Forms\TabSet) and [Tab](api:SilverStripe\Forms\Tab) objects and use jQuery Tabs to split parts of the data model. -[notice] -All interfaces within the CMS such as [ModelAdmin](api:SilverStripe\Admin\ModelAdmin) and [LeftAndMain](api:SilverStripe\Admin\LeftAndMain) use tabbed interfaces by default. -[/notice] +> [!WARNING] +> All interfaces within the CMS such as [ModelAdmin](api:SilverStripe\Admin\ModelAdmin) and [LeftAndMain](api:SilverStripe\Admin\LeftAndMain) use tabbed interfaces by default. When dealing with tabbed forms, modifying the fields in the form has a few differences. Each [Tab](api:SilverStripe\Forms\Tab) will be given a name, and normally they all exist under the `Root` [TabSet](api:SilverStripe\Forms\TabSet). -[notice] -[TabSet](api:SilverStripe\Forms\TabSet) instances can contain child [Tab](api:SilverStripe\Forms\Tab) and further [TabSet](api:SilverStripe\Forms\TabSet) instances, however the CMS UI will only -display up to two levels of tabs in the interface. -[/notice] +> [!WARNING] +> [TabSet](api:SilverStripe\Forms\TabSet) instances can contain child [Tab](api:SilverStripe\Forms\Tab) and further [TabSet](api:SilverStripe\Forms\TabSet) instances, however the CMS UI will only +> display up to two levels of tabs in the interface. ## Adding a field to a tab diff --git a/en/02_Developer_Guides/03_Forms/Field_types/02_DateField.md b/en/02_Developer_Guides/03_Forms/Field_types/02_DateField.md index 452f04110..c97f53f31 100644 --- a/en/02_Developer_Guides/03_Forms/Field_types/02_DateField.md +++ b/en/02_Developer_Guides/03_Forms/Field_types/02_DateField.md @@ -55,9 +55,8 @@ DateField::create('MyDate') ->setDateFormat('dd/MM/yyyy'); ``` -[info] -The formats are based on [ICU format](https://unicode-org.github.io/icu/userguide/format_parse/datetime/#simpledateformat). -[/info] +> [!NOTE] +> The formats are based on [ICU format](https://unicode-org.github.io/icu/userguide/format_parse/datetime/#simpledateformat). ## Min and max dates @@ -94,9 +93,8 @@ $dateField->setDescription(_t( $dateField->setAttribute('placeholder', $dateField->getDateFormat()); ``` -[notice] -Fields scaffolded through [DataObject::scaffoldCMSFields()](api:SilverStripe\ORM\DataObject::scaffoldCMSFields()) automatically have a description attached to them. -[/notice] +> [!WARNING] +> Fields scaffolded through [DataObject::scaffoldCMSFields()](api:SilverStripe\ORM\DataObject::scaffoldCMSFields()) automatically have a description attached to them. ## API documentation diff --git a/en/02_Developer_Guides/03_Forms/Field_types/03_HTMLEditorField.md b/en/02_Developer_Guides/03_Forms/Field_types/03_HTMLEditorField.md index 608d2fce1..f4138fca2 100644 --- a/en/02_Developer_Guides/03_Forms/Field_types/03_HTMLEditorField.md +++ b/en/02_Developer_Guides/03_Forms/Field_types/03_HTMLEditorField.md @@ -85,11 +85,10 @@ in the framework (and the `cms` module in case you've got that installed). There can be multiple configs, which should always be created / accessed using [TinyMCEConfig::get()](api:SilverStripe\Forms\HTMLEditor\TinyMCEConfig::get()). You can then set the currently active config using `set_active()`. -[notice] -Currently the order in which the `_config.php` files are executed depends on the module directory names. Execution -order is alphabetical, so if you set a TinyMCE option in the `aardvark/_config.php`, this will be overridden in -`vendor/silverstripe/framework/admin/_config.php` and your modification will disappear. -[/notice] +> [!WARNING] +> Currently the order in which the `_config.php` files are executed depends on the module directory names. Execution +> order is alphabetical, so if you set a TinyMCE option in the `aardvark/_config.php`, this will be overridden in +> `vendor/silverstripe/framework/admin/_config.php` and your modification will disappear. ## Adding and removing capabilities @@ -105,11 +104,10 @@ use SilverStripe\Forms\HTMLEditor\TinyMCEConfig; TinyMCEConfig::get('cms')->enablePlugins('media'); ``` -[notice] -This utilities the TinyMCE's `PluginManager::load` function under the hood (check the -[TinyMCE documentation on plugin loading](http://www.tinymce.com/wiki.php/API3:method.tinymce.AddOnManager.load) for -details). -[/notice] +> [!WARNING] +> This utilities the TinyMCE's `PluginManager::load` function under the hood (check the +> [TinyMCE documentation on plugin loading](http://www.tinymce.com/wiki.php/API3:method.tinymce.AddOnManager.load) for +> details). Plugins and advanced themes can provide additional buttons that can be added (or removed) through the configuration. Here is an example of adding a `ssmacron` button after the `charmap` button: @@ -130,11 +128,10 @@ use SilverStripe\Forms\HTMLEditor\TinyMCEConfig; TinyMCEConfig::get('cms')->removeButtons('tablecontrols', 'blockquote', 'hr'); ``` -[notice] -Internally [TinyMCEConfig](api:SilverStripe\Forms\HTMLEditor\TinyMCEConfig) uses the TinyMCE's `theme_advanced_buttons` option to configure these. See the -[TinyMCE documentation of this option](http://www.tinymce.com/wiki.php/Configuration:theme_advanced_buttons_1_n) -for more details. -[/notice] +> [!WARNING] +> Internally [TinyMCEConfig](api:SilverStripe\Forms\HTMLEditor\TinyMCEConfig) uses the TinyMCE's `theme_advanced_buttons` option to configure these. See the +> [TinyMCE documentation of this option](http://www.tinymce.com/wiki.php/Configuration:theme_advanced_buttons_1_n) +> for more details. ### Setting options @@ -163,10 +160,9 @@ TinyMCEConfig::get('cms')->setOption( ); ``` -[notice] -The default setting for the CMS's `extended_valid_elements` we are overriding here can be found in -`vendor/silverstripe/admin/_config.php`. -[/notice] +> [!WARNING] +> The default setting for the CMS's `extended_valid_elements` we are overriding here can be found in +> `vendor/silverstripe/admin/_config.php`. ## Writing custom plugins diff --git a/en/02_Developer_Guides/03_Forms/Field_types/04_GridField.md b/en/02_Developer_Guides/03_Forms/Field_types/04_GridField.md index 63c48b0b7..673a2c1a9 100644 --- a/en/02_Developer_Guides/03_Forms/Field_types/04_GridField.md +++ b/en/02_Developer_Guides/03_Forms/Field_types/04_GridField.md @@ -6,6 +6,9 @@ icon: table # `GridField` +> [!TIP] +> GridField can only be used with `$list` data sets that are of the type `SS_List` such as `DataList` or `ArrayList`. + [GridField](api:SilverStripe\Forms\GridField\GridField) is Silverstripe CMS's implementation of data grids. The main purpose of the `FormField` is to display tabular data in a format that is easy to view and modify. It can be thought of as a HTML table with some tricks. @@ -16,14 +19,9 @@ use SilverStripe\Forms\GridField\GridField; $field = GridField::create($name, $title, $list); ``` -[hint] -GridField can only be used with `$list` data sets that are of the type `SS_List` such as `DataList` or `ArrayList`. -[/hint] - -[notice] -[GridField](api:SilverStripe\Forms\GridField\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. -[/notice] +> [!WARNING] +> [GridField](api:SilverStripe\Forms\GridField\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. Each `GridField` is built from a number of components grouped into the [GridFieldConfig](api:SilverStripe\Forms\GridField\GridFieldConfig). Without any components, a `GridField` has almost no functionality. The `GridFieldConfig` instance and the attached [GridFieldComponent](api:SilverStripe\Forms\GridField\GridFieldComponent) are @@ -214,18 +212,16 @@ $gridField->setConfig($config); ### `GridFieldConfig_RecordViewer` +> [!CAUTION] +> The `DataObject` class displayed must define a `canView()` method that returns a boolean on whether the user can view +> this record. + Similar to `GridFieldConfig_Base` with the addition support of the ability to view a `GridFieldDetailForm` containing a read-only view of the data record. -[info] -The data row show must be a `DataObject` subclass. The fields displayed in the read-only view come from -`DataObject::getCMSFields()`. -[/info] - -[alert] -The `DataObject` class displayed must define a `canView()` method that returns a boolean on whether the user can view -this record. -[/alert] +> [!NOTE] +> The data row show must be a `DataObject` subclass. The fields displayed in the read-only view come from +> `DataObject::getCMSFields()`. ```php use SilverStripe\Forms\GridField\GridFieldConfig_RecordViewer; @@ -242,17 +238,15 @@ $gridField->setConfig($config); ### `GridFieldConfig_RecordEditor` -Similar to `GridFieldConfig_RecordViewer` with the addition support to edit or delete each of the records. +> [!CAUTION] +> Permission control for editing and deleting the record uses the `canEdit()` and `canDelete()` methods on the +> `DataObject` object. -[info] -The data row show must be a `DataObject` subclass. The fields displayed in the edit view come from -`DataObject::getCMSFields()`. -[/info] +Similar to `GridFieldConfig_RecordViewer` with the addition support to edit or delete each of the records. -[alert] -Permission control for editing and deleting the record uses the `canEdit()` and `canDelete()` methods on the -`DataObject` object. -[/alert] +> [!NOTE] +> The data row show must be a `DataObject` subclass. The fields displayed in the edit view come from +> `DataObject::getCMSFields()`. ```php use SilverStripe\Forms\GridField\GridFieldConfig_RecordEditor; @@ -444,10 +438,9 @@ Fragments are designated areas within a `GridField` which can be shared between your own fragments by using a `\$DefineFragment` placeholder in your components' template. This example will simply create an area rendered before the table wrapped in a simple `
`. -[notice] -Please note that in templates, you'll need to escape the dollar sign on `\$DefineFragment`. These are specially -processed placeholders as opposed to native template syntax. -[/notice] +> [!WARNING] +> Please note that in templates, you'll need to escape the dollar sign on `\$DefineFragment`. These are specially +> processed placeholders as opposed to native template syntax. ```php namespace App\Form\GridField; diff --git a/en/02_Developer_Guides/03_Forms/How_Tos/02_Lightweight_Form.md b/en/02_Developer_Guides/03_Forms/How_Tos/02_Lightweight_Form.md index 39b5870f6..f1f738893 100644 --- a/en/02_Developer_Guides/03_Forms/How_Tos/02_Lightweight_Form.md +++ b/en/02_Developer_Guides/03_Forms/How_Tos/02_Lightweight_Form.md @@ -61,6 +61,5 @@ class SearchPage extends Page `SearchForm.ss` will be executed within the scope of the `Form` object so has access to any of the methods and properties on [Form](api:SilverStripe\Forms\Form) such as `$Fields` and `$Actions`. -[notice] -To understand more about Scope or the syntax for custom templates, read the [Templates](../../templates) guide. -[/notice] +> [!WARNING] +> To understand more about Scope or the syntax for custom templates, read the [Templates](../../templates) guide. diff --git a/en/02_Developer_Guides/03_Forms/How_Tos/05_Simple_Contact_Form.md b/en/02_Developer_Guides/03_Forms/How_Tos/05_Simple_Contact_Form.md index acea35bd3..d30a8ab72 100644 --- a/en/02_Developer_Guides/03_Forms/How_Tos/05_Simple_Contact_Form.md +++ b/en/02_Developer_Guides/03_Forms/How_Tos/05_Simple_Contact_Form.md @@ -144,12 +144,11 @@ class ContactPageController extends PageController } ``` -[hint] - Caution: This form is prone to abuse by spammers, - since it doesn't enforce a rate limitation, or checks for bots. - We recommend to use a validation service like the ["recaptcha" module](https://www.silverstripe.org/spam-protection-module) - for better security. -[/hint] +> [!CAUTION] +> Caution: This form is prone to abuse by spammers, +> since it doesn't enforce a rate limitation, or checks for bots. +> We recommend to use a validation service like the ["recaptcha" module](https://www.silverstripe.org/spam-protection-module) +> for better security. Any function that receives a form submission takes two arguments: the data passed to the form as an indexed array, and the form itself. In order to extract the data, you can either use functions on the form object to get the fields and query their values, or just use the raw data in the array. In the example above, we used the array, as it's the easiest way to get data without requiring the form fields to perform any special transformations. diff --git a/en/02_Developer_Guides/04_Configuration/00_Configuration.md b/en/02_Developer_Guides/04_Configuration/00_Configuration.md index e85f10e17..01ea49cb9 100644 --- a/en/02_Developer_Guides/04_Configuration/00_Configuration.md +++ b/en/02_Developer_Guides/04_Configuration/00_Configuration.md @@ -18,9 +18,8 @@ properties API: - Configuration is normally set once during initialization and then not changed. - Configuration is normally set by a knowledgeable technical user, such as a developer, not the end user. -[notice] -For providing content editors or CMS users a place to manage configuration see the [SiteConfig](siteconfig) module. -[/notice] +> [!WARNING] +> For providing content editors or CMS users a place to manage configuration see the [SiteConfig](siteconfig) module. ## Configuration properties @@ -136,10 +135,9 @@ echo implode(', ', MyClass::config()->option_one); // returns 'Qux' ``` -[notice] -There is no way currently to restrict read or write access to any configuration property, or influence/check the values -being read or written. -[/notice] +> [!WARNING] +> There is no way currently to restrict read or write access to any configuration property, or influence/check the values +> being read or written. ## Configuration values @@ -170,11 +168,10 @@ Class\With\Array\Config: - If the value is not an array, the highest priority value is used without any attempt to merge -[alert] -The exception to this is "false-ish" values - empty arrays, empty strings, etc. When merging a non-false-ish value with -a false-ish value, the result will be the non-false-ish value regardless of priority. When merging two false-ish values -the result will be the higher priority false-ish value. -[/alert] +> [!CAUTION] +> The exception to this is "false-ish" values - empty arrays, empty strings, etc. When merging a non-false-ish value with +> a false-ish value, the result will be the non-false-ish value regardless of priority. When merging two false-ish values +> the result will be the higher priority false-ish value. The locations that configuration values are taken from in highest -> lowest priority order are: @@ -185,10 +182,9 @@ order, where the item that is latest is highest priority) - The composite configuration value of the parent class of this class - Any static set on an "additional static source" class (such as an extension) named the same as the name of the property -[notice] -It is an error to have mixed types of the same named property in different locations. An error will not necessarily -be raised due to optimizations in the lookup code. -[/notice] +> [!WARNING] +> It is an error to have mixed types of the same named property in different locations. An error will not necessarily +> be raised due to optimizations in the lookup code. ## Configuration masks @@ -214,18 +210,16 @@ bitwise `|` operator. ## Configuration YAML syntax and rules -[alert] -As of Silverstripe 4, YAML files can no longer be placed any deeper than 2 directories deep. As this was an unintended bug, this change will only affect you if you nest your modules deeper than the top level of your project. -[/alert] +> [!CAUTION] +> As of Silverstripe 4, YAML files can no longer be placed any deeper than 2 directories deep. As this was an unintended bug, this change will only affect you if you nest your modules deeper than the top level of your project. Each module can have a directory immediately underneath the main module directory called `_config/`. Inside this directory you can add YAML files that contain values for the configuration system. -[info] -The name of the files within the applications `_config` directly are arbitrary. Our examples use -`app/_config/app.yml` but you can break this file down into smaller files, or clearer patterns like `extensions.yml`, -`email.yml` if you want. For add-on's and modules, it is recommended that you name them with `.yml`. -[/info] +> [!NOTE] +> The name of the files within the applications `_config` directly are arbitrary. Our examples use +> `app/_config/app.yml` but you can break this file down into smaller files, or clearer patterns like `extensions.yml`, +> `email.yml` if you want. For add-on's and modules, it is recommended that you name them with `.yml`. The structure of each YAML file is a series of headers and values separated by YAML document separators. @@ -242,9 +236,8 @@ SilverStripe\Control\Director: --- ``` -[info] -If there is only one set of values the header can be omitted. -[/info] +> [!NOTE] +> If there is only one set of values the header can be omitted. Each value section of a YAML file has: @@ -310,10 +303,9 @@ after value sections with a name of `rootroutes`. However because `\*` has three In this case `\*` means "every value section *except* ones that have a fragment name of rootroutes". -[alert] -It is possible to create chains that are unsolvable. For instance, A must be before B, B must be before C, C must be -before A. In this case you will get an error when accessing your site. -[/alert] +> [!CAUTION] +> It is possible to create chains that are unsolvable. For instance, A must be before B, B must be before C, C must be +> before A. In this case you will get an error when accessing your site. ## Exclusionary rules @@ -381,11 +373,10 @@ Only: --- ``` -[alert] -When you have more than one rule for a nested fragment, they're joined like -`FRAGMENT_INCLUDED = (ONLY && ONLY) && !(EXCEPT && EXCEPT)`. -That is, the fragment will be included if all Only rules match, except if all Except rules match. -[/alert] +> [!CAUTION] +> When you have more than one rule for a nested fragment, they're joined like +> `FRAGMENT_INCLUDED = (ONLY && ONLY) && !(EXCEPT && EXCEPT)`. +> That is, the fragment will be included if all Only rules match, except if all Except rules match. ## Unit tests diff --git a/en/02_Developer_Guides/04_Configuration/01_SiteConfig.md b/en/02_Developer_Guides/04_Configuration/01_SiteConfig.md index b9902a04c..2cd05ca90 100644 --- a/en/02_Developer_Guides/04_Configuration/01_SiteConfig.md +++ b/en/02_Developer_Guides/04_Configuration/01_SiteConfig.md @@ -71,10 +71,9 @@ Silverstripe\SiteConfig\SiteConfig: - App\Extension\CustomSiteConfig ``` -[notice] -After adding the class and the YAML change, make sure to rebuild your database by visiting . -You may also need to reload the screen with a `?flush=1` i.e. . -[/notice] +> [!WARNING] +> After adding the class and the YAML change, make sure to rebuild your database by visiting . +> You may also need to reload the screen with a `?flush=1` i.e. . You can define as many extensions for `SiteConfig` as you need. For example, if you're developing a module and want to provide the users a place to configure settings then the `SiteConfig` panel is the place to go it. diff --git a/en/02_Developer_Guides/05_Extending/00_Modules.md b/en/02_Developer_Guides/05_Extending/00_Modules.md index 74500a750..4b1e778f2 100644 --- a/en/02_Developer_Guides/05_Extending/00_Modules.md +++ b/en/02_Developer_Guides/05_Extending/00_Modules.md @@ -50,9 +50,8 @@ Composer is using [version constraints](https://getcomposer.org/doc/articles/ver To lock down to a specific version, branch or commit, read up on ["lock" files](http://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file). -[notice] -After you add or remove modules, make sure you rebuild the database, class and configuration manifests by going to -[/notice] +> [!WARNING] +> After you add or remove modules, make sure you rebuild the database, class and configuration manifests by going to ## Creating a module {#create} diff --git a/en/02_Developer_Guides/05_Extending/01_Extensions.md b/en/02_Developer_Guides/05_Extending/01_Extensions.md index 358e9917b..130ffd411 100644 --- a/en/02_Developer_Guides/05_Extending/01_Extensions.md +++ b/en/02_Developer_Guides/05_Extending/01_Extensions.md @@ -13,10 +13,9 @@ trait applied within core, modules or even their own code to make it more reusab Extensions are defined as subclasses of either [DataExtension](api:SilverStripe\ORM\DataExtension) for extending a [DataObject](api:SilverStripe\ORM\DataObject) subclass or the [Extension](api:SilverStripe\Core\Extension) class for non DataObject subclasses (such as [Controller](api:SilverStripe\Control\Controller)) -[info] -For performance reasons a few classes are excluded from receiving extensions, including `ViewableData` -and `RequestHandler`. You can still apply extensions to descendants of these classes. -[/info] +> [!NOTE] +> For performance reasons a few classes are excluded from receiving extensions, including `ViewableData` +> and `RequestHandler`. You can still apply extensions to descendants of these classes. ```php // app/src/Extension/MyMemberExtension.php @@ -38,9 +37,8 @@ class MyMemberExtension extends DataExtension } ``` -[info] -Convention is for extension class names to end in `Extension`. This isn't a requirement but makes it clearer -[/info] +> [!NOTE] +> Convention is for extension class names to end in `Extension`. This isn't a requirement but makes it clearer After this class has been created, it does not yet apply it to any object. We need to tell Silverstripe CMS what classes we want to add the `MyMemberExtension` too. To activate this extension, add the following via the [Configuration API](../configuration). @@ -175,9 +173,8 @@ class MyMemberExtension extends DataExtension } ``` -[info] -The `$validator` parameter is passed by reference, as it is an object. -[/info] +> [!NOTE] +> The `$validator` parameter is passed by reference, as it is an object. Another common example of when you will want to modify a method is to update the default CMS fields for an object in an extension. The `CMS` provides a `updateCMSFields` Extension Hook to tie into. @@ -209,10 +206,9 @@ class MyMemberExtension extends DataExtension } ``` -[notice] -If you're providing a module or working on code that may need to be extended by other code, it should provide a *hook* -which allows an Extension to modify the results. -[/notice] +> [!WARNING] +> If you're providing a module or working on code that may need to be extended by other code, it should provide a *hook* +> which allows an Extension to modify the results. ```php namespace App\Model; @@ -257,9 +253,8 @@ class MyMemberExtension extends DataExtension } ``` -[notice] -Please note that while you can read protected properties of the source object (using `$this->owner->protectedProperty`) you cannot call any of it's protected methods (`$this->owner->protectedMethod()` will not work). You also cannot access any of the source object's private properties or methods (`$this->owner->privateProperty` will not work either). -[/notice] +> [!WARNING] +> Please note that while you can read protected properties of the source object (using `$this->owner->protectedProperty`) you cannot call any of it's protected methods (`$this->owner->protectedMethod()` will not work). You also cannot access any of the source object's private properties or methods (`$this->owner->privateProperty` will not work either). ## Checking to see if an object has an extension @@ -284,10 +279,9 @@ callback to be executed immediately before and after `extend()` is called on ext This is useful in many cases where working with modules such as `Translatable` which operate on `DataObject` fields that must exist in the `FieldList` at the time that `$this->extend('UpdateCMSFields')` is called. -[notice] -Please note that each callback is only ever called once, and then cleared, so multiple extensions to the same function -require that a callback is registered each time, if necessary. -[/notice] +> [!WARNING] +> Please note that each callback is only ever called once, and then cleared, so multiple extensions to the same function +> require that a callback is registered each time, if necessary. Example: A class that wants to control default values during object initialization. The code needs to assign a value if not specified in `self::$defaults`, but before extensions have been called: @@ -318,9 +312,8 @@ class MyModel extends DataObject Example 2: User code can intervene in the process of extending CMS fields. -[notice] -This method is preferred to disabling, enabling, and calling field extensions manually. -[/notice] +> [!WARNING] +> This method is preferred to disabling, enabling, and calling field extensions manually. ```php namespace App\Model; @@ -374,12 +367,11 @@ class CustomisedSomeExtension extends SomeExtension } ``` -[notice] -Please note that modifications such as this should be done in YAML configuration only. It is not recommended -to use `Config::modify()->set()` to adjust the implementation class name of an extension after the configuration -manifest has been loaded, and may not work consistently due to the "extra methods" cache having already been -populated. -[/notice] +> [!WARNING] +> Please note that modifications such as this should be done in YAML configuration only. It is not recommended +> to use `Config::modify()->set()` to adjust the implementation class name of an extension after the configuration +> manifest has been loaded, and may not work consistently due to the "extra methods" cache having already been +> populated. ## Related lessons diff --git a/en/02_Developer_Guides/05_Extending/04_Shortcodes.md b/en/02_Developer_Guides/05_Extending/04_Shortcodes.md index 3851769b6..b36526da2 100644 --- a/en/02_Developer_Guides/05_Extending/04_Shortcodes.md +++ b/en/02_Developer_Guides/05_Extending/04_Shortcodes.md @@ -63,15 +63,14 @@ class MyShortCodeProvider } ``` -[warning] -Note that the `$arguments` parameter potentially contains any arbitrary key/value pairs the user has chosen to include. -It is strongly recommended that you don't directly convert this array into a list of attributes for your final HTML markup -as that could lead to XSS vulnerabilities in your project. - -If you want to use the `$arguments` parameter as a list of attributes for your final HTML markup, it is strongly recommended that you -pass the array through a filter of allowed arguments using [array_filter()](https://www.php.net/manual/en/function.array-filter.php) -or similar. -[/warning] +> [!WARNING] +> Note that the `$arguments` parameter potentially contains any arbitrary key/value pairs the user has chosen to include. +> It is strongly recommended that you don't directly convert this array into a list of attributes for your final HTML markup +> as that could lead to XSS vulnerabilities in your project. +> +> If you want to use the `$arguments` parameter as a list of attributes for your final HTML markup, it is strongly recommended that you +> pass the array through a filter of allowed arguments using [array_filter()](https://www.php.net/manual/en/function.array-filter.php) +> or similar. These parameters are passed to the `parseMyShortCode` callback: diff --git a/en/02_Developer_Guides/05_Extending/05_Injector.md b/en/02_Developer_Guides/05_Extending/05_Injector.md index 619cbb9e6..e20b4cef9 100644 --- a/en/02_Developer_Guides/05_Extending/05_Injector.md +++ b/en/02_Developer_Guides/05_Extending/05_Injector.md @@ -89,9 +89,8 @@ $client = Injector::inst()->get(MyClient::class); // $client is now an instance of WriteClient ``` -[info] -Note that 'MyClient' [does not have to be an existing class](#service-inheritance) - you could use an abitrary string to identify it. That said using existing classes can be easier to reason about and can be refactored by automatic tools/IDEs. -[/info] +> [!NOTE] +> Note that 'MyClient' [does not have to be an existing class](#service-inheritance) - you could use an abitrary string to identify it. That said using existing classes can be easier to reason about and can be refactored by automatic tools/IDEs. Using Injector imperatively like this is most common [in testing](#testing-with-injector). @@ -119,9 +118,8 @@ $object = Injector::inst()->get(MyClass::class); This allows you to concisely override classes in Silverstripe core or other third-party Silverstripe code. -[info] -When overriding other configuration beware the [order that configuration is applied](../configuration/#configuration-values). You may have to use the [Before/After](../configuration/#before-after-priorities) syntax to apply your override. -[/info] +> [!NOTE] +> When overriding other configuration beware the [order that configuration is applied](../configuration/#configuration-values). You may have to use the [Before/After](../configuration/#before-after-priorities) syntax to apply your override. ### Special YAML syntax @@ -172,7 +170,8 @@ SilverStripe\Core\Injector\Injector: secret: '`SS_API_CLIENT_SECRET`' ``` -[info]Note: undefined variables will be replaced with null.[/info] +> [!NOTE] +> Note: undefined variables will be replaced with null. ## Dependencies @@ -204,9 +203,8 @@ class MyController extends Controller } ``` -[info] -Note that using public properties instead of setter methods is also supported, though setter methods are generally preferred for code quality reasons. -[/info] +> [!NOTE] +> Note that using public properties instead of setter methods is also supported, though setter methods are generally preferred for code quality reasons. When creating a new instance of `App\Control\MyController` via Injector the permissions property will contain an instance of the `ThirdParty\PermissionService` that was resolved by Injector. diff --git a/en/02_Developer_Guides/05_Extending/06_Aspects.md b/en/02_Developer_Guides/05_Extending/06_Aspects.md index da341f702..d763df7cd 100644 --- a/en/02_Developer_Guides/05_Extending/06_Aspects.md +++ b/en/02_Developer_Guides/05_Extending/06_Aspects.md @@ -13,10 +13,6 @@ Aspect oriented programming is the idea that some logic abstractions can be appl > functions from the main program's business logic. It aims to increase modularity by allowing the separation of > cross-cutting concerns, forming a basis for aspect-oriented software development. -[notice] -[Wikipedia](http://en.wikipedia.org/wiki/Aspect-oriented_programming) provides a much more in-depth explanation. -[/notice] - In the context of the Silverstripe CMS [Dependency Injector](injector), Aspects are achieved thanks to PHP's `__call` magic method combined with the `Proxy` Design Pattern. @@ -41,10 +37,9 @@ specific database server, whereas all read queries can be handled by slave serve A simplified implementation might look like the following. -[notice] -This doesn't cover all cases used by Silverstripe CMS so is not a complete solution, more just a guide to how it would be +> [!WARNING] +> This doesn't cover all cases used by Silverstripe CMS so is not a complete solution, more just a guide to how it would be used. -[/notice] ```php // app/src/Aspect/MySQLWriteDbAspect.php diff --git a/en/02_Developer_Guides/05_Extending/How_Tos/01_Publish_a_Module.md b/en/02_Developer_Guides/05_Extending/How_Tos/01_Publish_a_Module.md index 2ab7b7712..5f4a3c9e6 100644 --- a/en/02_Developer_Guides/05_Extending/How_Tos/01_Publish_a_Module.md +++ b/en/02_Developer_Guides/05_Extending/How_Tos/01_Publish_a_Module.md @@ -91,9 +91,8 @@ Say you have a module which supports Silverstripe CMS 3.0. A new release of this in Silverstripe CMS 3.1. In this case, you would create a new branch for the 3.0 compatible code base of your module. This allows you to continue fixing bugs on this older release branch. -[info] -As a convention, the `master` branch of your module should always work with the `master` branch of Silverstripe CMS. -[/info] +> [!NOTE] +> As a convention, the `master` branch of your module should always work with the `master` branch of Silverstripe CMS. Other branches should be created on your module as needed if they're required to support specific Silverstripe CMS releases. diff --git a/en/02_Developer_Guides/06_Testing/00_Unit_Testing.md b/en/02_Developer_Guides/06_Testing/00_Unit_Testing.md index faf69250b..b4eef10e5 100644 --- a/en/02_Developer_Guides/06_Testing/00_Unit_Testing.md +++ b/en/02_Developer_Guides/06_Testing/00_Unit_Testing.md @@ -39,44 +39,40 @@ class PageTest extends SapphireTest } ``` -[info] -Tests for your application should be stored in the `app/tests` directory. Test cases for add-ons should be stored in -the `(modulename)/tests` directory. - -Test case classes should end with `Test` (e.g. `PageTest`) and test methods must start with `test` (e.g. `testMyMethod`). - -Ensure you [import](http://php.net/manual/en/language.namespaces.importing.php#example-252) any classes you need for the test, including `SilverStripe\Dev\SapphireTest` or `SilverStripe\Dev\FunctionalTest`. -[/info] +> [!NOTE] +> Tests for your application should be stored in the `app/tests` directory. Test cases for add-ons should be stored in +> the `(modulename)/tests` directory. +> +> Test case classes should end with `Test` (e.g. `PageTest`) and test methods must start with `test` (e.g. `testMyMethod`). +> +> Ensure you [import](http://php.net/manual/en/language.namespaces.importing.php#example-252) any classes you need for the test, including `SilverStripe\Dev\SapphireTest` or `SilverStripe\Dev\FunctionalTest`. A Silverstripe CMS unit test is created by extending one of two classes, [SapphireTest](api:SilverStripe\Dev\SapphireTest) or [FunctionalTest](api:SilverStripe\Dev\FunctionalTest). [SapphireTest](api:SilverStripe\Dev\SapphireTest) is used to test your model logic (such as a `DataObject`), and [FunctionalTest](api:SilverStripe\Dev\FunctionalTest) is used when you want to test a `Controller`, `Form` or anything that requires a web page. -[info] -`FunctionalTest` is a subclass of `SapphireTest` so will inherit all of the behaviors. By subclassing `FunctionalTest` -you gain the ability to load and test web pages on the site. - -`SapphireTest` in turn, extends `PHPUnit\Framework\TestCase`. For more information on `PHPUnit\Framework\TestCase` see -the [PHPUnit](http://www.phpunit.de) documentation. It provides a lot of fundamental concepts that we build on in this -documentation. -[/info] +> [!NOTE] +> `FunctionalTest` is a subclass of `SapphireTest` so will inherit all of the behaviors. By subclassing `FunctionalTest` +> you gain the ability to load and test web pages on the site. +> +> `SapphireTest` in turn, extends `PHPUnit\Framework\TestCase`. For more information on `PHPUnit\Framework\TestCase` see +> the [PHPUnit](http://www.phpunit.de) documentation. It provides a lot of fundamental concepts that we build on in this +> documentation. ## Test databases and fixtures +> [!CAUTION] +> As the test runner will create new databases for the tests to run, the database user should have the appropriate +> permissions to create new databases on your server. + Silverstripe CMS tests create their own database when the test starts and fixture files are specified. New `ss_tmp` databases are created using the same connection details you provide for the main website. The new `ss_tmp` database does not copy what is currently in your application database. To provide seed data use a [Fixture](fixtures) file. -[alert] -As the test runner will create new databases for the tests to run, the database user should have the appropriate -permissions to create new databases on your server. -[/alert] - -[notice] -The test database is rebuilt every time one of the test methods is run and is removed afterwards. If the test is interrupted, the database will not be removed. Over time, you may have several hundred test -databases on your machine. To get rid of them, run `sake dev/tasks/CleanupTestDatabasesTask`. -[/notice] +> [!CAUTION] +> The test database is rebuilt every time one of the test methods is run and is removed afterwards. If the test is interrupted, the database will not be removed. Over time, you may have several hundred test +> databases on your machine. To get rid of them, run `sake dev/tasks/CleanupTestDatabasesTask`. ## Custom PHPUnit configuration diff --git a/en/02_Developer_Guides/06_Testing/01_Functional_Testing.md b/en/02_Developer_Guides/06_Testing/01_Functional_Testing.md index 4f5356af3..e92704bc4 100644 --- a/en/02_Developer_Guides/06_Testing/01_Functional_Testing.md +++ b/en/02_Developer_Guides/06_Testing/01_Functional_Testing.md @@ -27,10 +27,9 @@ $page = $this->post($url); Performs a POST request on `$url` and retrieves the [HTTPResponse](api:SilverStripe\Control\HTTPResponse). This also changes the current page to the value of the response. -[notice] -Previous versions of Silverstripe CMS would send a GET request if `post()` was called with no POST variables supplied in the second argument. -Silverstripe CMS 4.6 and later always sends a POST request for consistency. -[/notice] +> [!WARNING] +> Previous versions of Silverstripe CMS would send a GET request if `post()` was called with no POST variables supplied in the second argument. +> Silverstripe CMS 4.6 and later always sends a POST request for consistency. ## Other requests @@ -106,9 +105,8 @@ Assert that the most recently queried page contains a number of content tags spe selector will be applied to the HTML of the most recent page. The content of every matching tag will be examined. The assertion fails if one of the expectedMatches fails to appear. -[notice] -` ` characters are stripped from the content; make sure that your assertions take this into account. -[/notice] +> [!WARNING] +> ` ` characters are stripped from the content; make sure that your assertions take this into account. ### `assertExactHTMLMatchBySelector` @@ -122,9 +120,8 @@ Assert that the most recently queried page contains a number of content tags spe selector will be applied to the HTML of the most recent page. The full HTML of every matching tag will be examined. The assertion fails if one of the expectedMatches fails to appear. -[notice] -` ` characters are stripped from the content; make sure that your assertions take this into account. -[/notice] +> [!WARNING] +> ` ` characters are stripped from the content; make sure that your assertions take this into account. ## Related documentation diff --git a/en/02_Developer_Guides/06_Testing/04_Fixtures.md b/en/02_Developer_Guides/06_Testing/04_Fixtures.md index 6481d9eba..30b97112a 100644 --- a/en/02_Developer_Guides/06_Testing/04_Fixtures.md +++ b/en/02_Developer_Guides/06_Testing/04_Fixtures.md @@ -139,19 +139,12 @@ seen by the fields prefixed with `=>`. Each one of our Players has a relationship to a Team, this is shown with the `Team` field for each `Player` being set to `=>App\Test\Team.` followed by a team name. -[info] -Take the player John in our example YAML, his team is the Hurricanes which is represented by `=>App\Test\Team.hurricanes`. This +Take the player John in our example YAML below, his team is the Hurricanes which is represented by `=>App\Test\Team.hurricanes`. This sets the `has_one` relationship for John with with the `Team` object `hurricanes`. -[/info] -[hint] -Note that we use the name of the relationship (Team), and not the name of the -database field (TeamID). -[/hint] - -[hint] -Also be aware the target of a relationship must be defined before it is referenced, for example the `hurricanes` team must appear in the fixture file before the line `Team: =>App\Test\Team.hurricanes`. -[/hint] +> [!TIP] +> Note that we use the name of the relationship (Team), and not the name of the +> database field (TeamID). This style of relationship declaration can be used for any type of relationship (i.e. `has_one`, `has_many`, `many_many`). @@ -176,6 +169,9 @@ App\Test\Team: Players: =>App\Test\Player.joe,=>App\Test\Player.jack ``` +> [!WARNING] +> Be aware the target of a relationship must be defined before it is referenced, for example the `hurricanes` team must appear in the fixture file before the line `Team: =>App\Test\Team.hurricanes`. + The database is populated by instantiating `DataObject` objects and setting the fields declared in the `YAML`, then calling `write()` on those objects. Take for instance the `hurricances` record in the `YAML`. It is equivalent to writing: @@ -193,10 +189,9 @@ $team->write(); $team->Players()->add($john); ``` -[notice] -As the YAML fixtures will call `write`, any `onBeforeWrite()` or default value logic will be executed as part of the -test. -[/notice] +> [!WARNING] +> As the YAML fixtures will call `write`, any `onBeforeWrite()` or default value logic will be executed as part of the +> test. ## Fixtures for namespaced classes @@ -213,9 +208,8 @@ App\Test\Team: Players: =>App\Test\Player.john ``` -[notice] -If your tests are failing and your database has table names that follow the fully qualified class names, you've probably forgotten to implement `private static $table_name = 'Player';` on your namespaced class. This property was introduced in Silverstripe CMS 4 to reduce data migration work. See [DataObject](api:SilverStripe\ORM\DataObject) for an example. -[/notice] +> [!WARNING] +> If your tests are failing and your database has table names that follow the fully qualified class names, you've probably forgotten to implement `private static $table_name = 'Player';` on your namespaced class. This property was introduced in Silverstripe CMS 4 to reduce data migration work. See [DataObject](api:SilverStripe\ORM\DataObject) for an example. ## Defining many_many_extraFields @@ -295,9 +289,8 @@ While manually defined fixtures provide full flexibility, they offer very little Alternatively, you can use the [FixtureFactory](api:SilverStripe\Dev\FixtureFactory) class, which allows you to set default values, callbacks on object creation, and dynamic/lazy value setting. -[hint] -`SapphireTest` uses `FixtureFactory` under the hood when it is provided with YAML based fixtures. -[/hint] +> [!TIP] +> `SapphireTest` uses `FixtureFactory` under the hood when it is provided with YAML based fixtures. The idea is that rather than instantiating objects directly, we'll have a factory class for them. This factory can have *blueprints* defined on it, which tells the factory how to instantiate an object of a specific type. Blueprints need a @@ -325,10 +318,9 @@ $obj = $factory->createObject(Team::class, 'hurricanes', [ ]); ``` -[warning] -It is important to remember that fixtures are referenced by arbitrary identifiers ('hurricanes'). These are internally -mapped to their database identifiers. -[/warning] +> [!WARNING] +> It is important to remember that fixtures are referenced by arbitrary identifiers ('hurricanes'). These are internally +> mapped to their database identifiers. After we've created this object in the factory, `getId` is used to retrieve it by the identifier. diff --git a/en/02_Developer_Guides/06_Testing/How_Tos/00_Write_a_SapphireTest.md b/en/02_Developer_Guides/06_Testing/How_Tos/00_Write_a_SapphireTest.md index 9598af202..b43e65db4 100644 --- a/en/02_Developer_Guides/06_Testing/How_Tos/00_Write_a_SapphireTest.md +++ b/en/02_Developer_Guides/06_Testing/How_Tos/00_Write_a_SapphireTest.md @@ -85,17 +85,15 @@ Firstly we define a static `$fixture_file`, this should point to a file that rep represented as a YAML [Fixture](../fixtures). When our test is run, the data from this file will be loaded into a test database and discarded at the end of the test. -[notice] -The `fixture_file` property can be path to a file, or an array of strings pointing to many files. The path must be -absolute from your website's root folder. -[/notice] +> [!WARNING] +> The `fixture_file` property can be path to a file, or an array of strings pointing to many files. The path must be +> absolute from your website's root folder. The second part of our class is the `testURLGeneration` method. This method is our test. When the test is executed, methods prefixed with the word `test` will be run. -[notice] -The test database is rebuilt every time one of these methods is run. -[/notice] +> [!WARNING] +> The test database is rebuilt every time one of these methods is run. Inside our test method is the `objFromFixture` method that will generate an object for us based on data from our fixture file. To identify to the object, we provide a class name and an identifier. The identifier is specified in the YAML file @@ -116,9 +114,8 @@ Just like on web requests, Silverstripe CMS caches metadata about the execution vendor/bin/phpunit app/tests/PageTest.php '' flush=1 ``` -[info] -For more information on PHPUnit's assertions see the [PHPUnit manual](http://www.phpunit.de/manual/current/en/api.html#api.assert). -[/info] +> [!NOTE] +> For more information on PHPUnit's assertions see the [PHPUnit manual](http://www.phpunit.de/manual/current/en/api.html#api.assert). ## Related documentation diff --git a/en/02_Developer_Guides/07_Debugging/00_Environment_Types.md b/en/02_Developer_Guides/07_Debugging/00_Environment_Types.md index becdbe130..d86f8b135 100644 --- a/en/02_Developer_Guides/07_Debugging/00_Environment_Types.md +++ b/en/02_Developer_Guides/07_Debugging/00_Environment_Types.md @@ -17,11 +17,10 @@ When developing your websites, adding page types or installing modules you shoul you will see full error back traces and view the development tools without having to be logged in as an administrator user. -[alert] -**dev mode should not be enabled long term on live sites for security reasons**. In dev mode by outputting back traces -of function calls a hacker can gain information about your environment (including passwords) so you should use dev mode -on a public server very carefully. -[/alert] +> [!CAUTION] +> **dev mode should not be enabled long term on live sites for security reasons**. In dev mode by outputting back traces +> of function calls a hacker can gain information about your environment (including passwords) so you should use dev mode +> on a public server very carefully. ## Test mode @@ -50,9 +49,8 @@ When using CGI/FastCGI with Apache, you will have to add the `RewriteRule .* - [ All error messages are suppressed from the user and the application is in it's most *secure* state. -[alert] -Live sites should always run in live mode. You should not run production websites in dev mode. -[/alert] +> [!CAUTION] +> Live sites should always run in live mode. You should not run production websites in dev mode. ## Checking environment type diff --git a/en/02_Developer_Guides/07_Debugging/01_Error_Handling.md b/en/02_Developer_Guides/07_Debugging/01_Error_Handling.md index 86116f2cc..5d375277d 100644 --- a/en/02_Developer_Guides/07_Debugging/01_Error_Handling.md +++ b/en/02_Developer_Guides/07_Debugging/01_Error_Handling.md @@ -164,6 +164,9 @@ The calls key, `MailHandler`, can be anything you like: its main purpose is to l ### Logging to a file +> [!WARNING] +> You will need to make sure the user running the PHP process has write access to the log file, wherever you choose to put it. + To log to a file, you can use Monolog's [StreamHandler](https://github.com/Seldaek/monolog/blob/master/src/Monolog/Handler/StreamHandler.php#L74), like this: ```yml @@ -178,19 +181,14 @@ SilverStripe\Core\Injector\Injector: - "info" ``` -[warning] -The log file path must be an absolute file path, as relative paths may behave differently between CLI and HTTP requests. If you want to use a *relative* path, you can use the `SS_ERROR_LOG` environment variable to declare a file path that is relative to your project root: - -```bash -SS_ERROR_LOG="./silverstripe.log" -``` - -You don't need any of the YAML configuration above if you are using the `SS_ERROR_LOG` environment variable - but you can use a combination of the environment variable and YAML configuration if you want to configure multiple error log files. -[/warning] - -[notice] -You will need to make sure the user running the PHP process has write access to the log file, wherever you choose to put it. -[/notice] +> [!WARNING] +> The log file path must be an absolute file path, as relative paths may behave differently between CLI and HTTP requests. If you want to use a *relative* path, you can use the `SS_ERROR_LOG` environment variable to declare a file path that is relative to your project root: +> +> ```bash +> SS_ERROR_LOG="./silverstripe.log" +> ``` +> +> You don't need any of the YAML configuration above if you are using the `SS_ERROR_LOG` environment variable - but you can use a combination of the environment variable and YAML configuration if you want to configure multiple error log files. The `info` argument provides the minimum level to start logging at. @@ -275,11 +273,10 @@ SilverStripe\Core\Injector\Injector: Body: "The website server has not been able to respond to your request" ``` -[info] -In addition to Silverstripe CMS integrated logging, it is advisable to fall back to PHP's native logging functionality. A -script might terminate before it reaches the Silverstripe CMS error handling, for example in the case of a fatal error. Make -sure `log_errors` and `error_log` in your PHP ini file are configured. -[/info] +> [!NOTE] +> In addition to Silverstripe CMS integrated logging, it is advisable to fall back to PHP's native logging functionality. A +> script might terminate before it reaches the Silverstripe CMS error handling, for example in the case of a fatal error. Make +> sure `log_errors` and `error_log` in your PHP ini file are configured. ## Replacing default implementations diff --git a/en/02_Developer_Guides/08_Performance/00_Partial_Caching.md b/en/02_Developer_Guides/08_Performance/00_Partial_Caching.md index 557b719af..6b9f3d9c3 100644 --- a/en/02_Developer_Guides/08_Performance/00_Partial_Caching.md +++ b/en/02_Developer_Guides/08_Performance/00_Partial_Caching.md @@ -13,9 +13,8 @@ icon: tachometer-alt Use conditions whenever possible. The cache tag supports defining conditions via either `if` or `unless` keyword. Those are optional, however is highly recommended. -[warning] -Avoid performing heavy computations in conditionals, as they are evaluated for every template rendering. -[/warning] +> [!WARNING] +> Avoid performing heavy computations in conditionals, as they are evaluated for every template rendering. If you cache without conditions: @@ -62,57 +61,50 @@ otherwise. By using aggregates, we do that like this: %> ``` -The cache for this will update whenever a page is added, removed or edited. - -[note] -The use of the fully qualified classname is necessary. -[/note] - -[note] -The use of both `.max('LastEdited')` and `.count()` makes sure we check for any object -edited or deleted since the cache was last built. -[/note] - -[warning] -Be careful using aggregates. Remember that the database is usually one of the performance bottlenecks. -Keep in mind that every key of every cached block is recalculated for every template render, regardless of caching -result. Aggregating SQL queries are usually produce more load on the database than simple select queries, -especially if you query records by Primary Key or join tables using database indices properly. - -Sometimes it may be cheaper to not cache altogether, rather than cache a block using a bunch of heavy aggregating SQL -queries. - -Let us consider two versions: - -```ss -# Version 1 (bad) - -<% cached - $List('SilverStripe\CMS\Model\SiteTree').max('LastEdited'), - $List('SilverStripe\CMS\Model\SiteTree').count() -%> - Parent title is: $Me.Parent.Title -<% end_cached %> -``` - -```ss -# Version 2 (better performance than Version 1) - -Parent title is: $Me.Parent.Title -``` - -`Version 1` always generates two heavy aggregating SQL queries for the database on every -template render. -`Version 2` always generates a single and more performant SQL query fetching the record by its Primary Key. +> [!NOTE] +> The use of the fully qualified classname is necessary. +> +> The use of both `.max('LastEdited')` and `.count()` makes sure we check for any object +> edited or deleted since the cache was last built. -[/warning] +The cache for this will update whenever a page is added, removed or edited. -[warning] -If you use the same aggregate in a template more than once, it will be recalculated every time -unless you move it out into a separate -[controller method](../templates/partial_template_caching/#cache-key-calculated-in-controller). -[Object Caching](../templates/caching/#object-caching) only works for single variables and not for chained expressions. -[/warning] +> [!WARNING] +> Be careful using aggregates. Remember that the database is usually one of the performance bottlenecks. +> Keep in mind that every key of every cached block is recalculated for every template render, regardless of caching +> result. Aggregating SQL queries are usually produce more load on the database than simple select queries, +> especially if you query records by Primary Key or join tables using database indices properly. +> +> Sometimes it may be cheaper to not cache altogether, rather than cache a block using a bunch of heavy aggregating SQL +> queries. +> +> Let us consider two versions: +> +> ```ss +> # Version 1 (bad) +> +> <% cached +> $List('SilverStripe\CMS\Model\SiteTree').max('LastEdited'), +> $List('SilverStripe\CMS\Model\SiteTree').count() +> %> +> Parent title is: $Me.Parent.Title +> <% end_cached %> +> ``` +> +> ```ss +> # Version 2 (better performance than Version 1) +> +> Parent title is: $Me.Parent.Title +> ``` +> +> `Version 1` always generates two heavy aggregating SQL queries for the database on every +> template render. +> `Version 2` always generates a single and more performant SQL query fetching the record by its Primary Key. +> +> Note also that if you use the same aggregate in a template more than once, it will be recalculated every time +> unless you move it out into a separate +> [controller method](../templates/partial_template_caching/#cache-key-calculated-in-controller). +> [Object Caching](../templates/caching/#object-caching) only works for single variables and not for chained expressions. ## Purposely stale data @@ -163,6 +155,9 @@ All you need to do to swap the cache backend for partial template cache blocks i Here's an example of how it could be done: +> [!NOTE] +> For the below example to work it is necessary to have the Injector service `App\Cache\Service.memcached` defined somewhere in the configs. + ```yml # app/_config/cache.yml --- @@ -174,12 +169,7 @@ SilverStripe\Core\Injector\Injector: Psr\SimpleCache\CacheInterface.cacheblock: '%$App\Cache\Service.memcached' ``` -[note] -For the above example to work it is necessary to have the Injector service `App\Cache\Service.memcached` defined somewhere in the configs. -[/note] - -[warning] -The default filesystem cache backend does not support auto cleanup of the residual files with expired cache records. -If your project relies on Template Caching heavily (e.g. thousands of cache records daily), you may want to keep en eye on the -filesystem storage. Sooner or later its capacity may be exhausted. -[/warning] +> [!WARNING] +> The default filesystem cache backend does not support auto cleanup of the residual files with expired cache records. +> If your project relies on Template Caching heavily (e.g. thousands of cache records daily), you may want to keep en eye on the +> filesystem storage. Sooner or later its capacity may be exhausted. diff --git a/en/02_Developer_Guides/08_Performance/01_Caching.md b/en/02_Developer_Guides/08_Performance/01_Caching.md index 0cada0346..4fda63dba 100644 --- a/en/02_Developer_Guides/08_Performance/01_Caching.md +++ b/en/02_Developer_Guides/08_Performance/01_Caching.md @@ -48,12 +48,11 @@ SilverStripe\Core\Injector\Injector: namespace: "myCache" ``` -[alert] -Please note that if you have the `silverstripe/versioned` module installed (automatically installed by the -`silverstripe/cms` module), caches will automatically be segmented by current “stage”. This ensures that -any content written to the cache in the *draft* reading mode isn’t accidentally exposed in the *live* reading mode. -Please read the [versioned cache segmentation](#versioned-cache-segmentation) section for more information. -[/alert] +> [!CAUTION] +> Please note that if you have the `silverstripe/versioned` module installed (automatically installed by the +> `silverstripe/cms` module), caches will automatically be segmented by current “stage”. This ensures that +> any content written to the cache in the *draft* reading mode isn’t accidentally exposed in the *live* reading mode. +> Please read the [versioned cache segmentation](#versioned-cache-segmentation) section for more information. Cache objects are instantiated through a [CacheFactory](SilverStripe\Core\Cache\CacheFactory), which determines which cache adapter is used (see "Adapters" below for details). diff --git a/en/02_Developer_Guides/08_Performance/04_Static_Publishing.md b/en/02_Developer_Guides/08_Performance/04_Static_Publishing.md index 114206fd0..c85e33eaf 100644 --- a/en/02_Developer_Guides/08_Performance/04_Static_Publishing.md +++ b/en/02_Developer_Guides/08_Performance/04_Static_Publishing.md @@ -9,10 +9,9 @@ One of the best ways to get the top performance out of Silverstripe CMS is to by time, connecting to the database and formatting your templates. This is only appropriate approach on web pages that have completely static content. -[info] -If you want to cache part of a page, or your site has interactive elements such as forms, then -[Partial Caching](partial_caching) is more suitable. -[/info] +> [!NOTE] +> If you want to cache part of a page, or your site has interactive elements such as forms, then +> [Partial Caching](partial_caching) is more suitable. By publishing the page as HTML it's possible to run Silverstripe CMS from behind a corporate firewall, on a low performance server or serve millions of hits an hour without expensive hardware. diff --git a/en/02_Developer_Guides/08_Performance/05_Resource_Usage.md b/en/02_Developer_Guides/08_Performance/05_Resource_Usage.md index a8bf921b5..a7e26e51f 100644 --- a/en/02_Developer_Guides/08_Performance/05_Resource_Usage.md +++ b/en/02_Developer_Guides/08_Performance/05_Resource_Usage.md @@ -13,18 +13,16 @@ These limits are defined through `memory_limit` and `max_execution_time` in the overwritten through `ini_set()`, unless PHP is running with the [Suhoshin Patches](http://www.hardened-php.net/) or in "[safe mode](http://php.net/manual/en/features.safe-mode.php)". -[alert] -Most shared hosting providers will have maximum values that can't be altered. -[/alert] +> [!CAUTION] +> Most shared hosting providers will have maximum values that can't be altered. For certain tasks like synchronizing a large `assets/` folder with all file and folder entries in the database, more resources are required temporarily. In general, we recommend running resource intensive tasks through the [command line](../cli), where configuration defaults for these settings are higher or even unlimited. -[info] -Silverstripe CMS can request more resources through `Environment::increaseMemoryLimitTo()` and -`Environment::increaseTimeLimitTo()` functions. -[/info] +> [!NOTE] +> Silverstripe CMS can request more resources through `Environment::increaseMemoryLimitTo()` and +> `Environment::increaseTimeLimitTo()` functions. ```php use SilverStripe\Core\Environment; diff --git a/en/02_Developer_Guides/09_Security/00_Member.md b/en/02_Developer_Guides/09_Security/00_Member.md index 2689dba81..f775c243c 100644 --- a/en/02_Developer_Guides/09_Security/00_Member.md +++ b/en/02_Developer_Guides/09_Security/00_Member.md @@ -29,10 +29,9 @@ if ($member) { ## Subclassing -[warning] -This is the least desirable way of extending the [Member](api:SilverStripe\Security\Member) class. It's better to use [DataExtension](api:SilverStripe\ORM\DataExtension) -(see below). -[/warning] +> [!WARNING] +> This is the least desirable way of extending the [Member](api:SilverStripe\Security\Member) class. It's better to use [DataExtension](api:SilverStripe\ORM\DataExtension) +> (see below). You can define subclasses of [Member](api:SilverStripe\Security\Member) to add extra fields or functionality to the built-in membership system. diff --git a/en/02_Developer_Guides/09_Security/04_Secure_Coding.md b/en/02_Developer_Guides/09_Security/04_Secure_Coding.md index 78329e303..af9079e63 100644 --- a/en/02_Developer_Guides/09_Security/04_Secure_Coding.md +++ b/en/02_Developer_Guides/09_Security/04_Secure_Coding.md @@ -103,10 +103,9 @@ $members = Member::get()->where(['"Name" = ?' => $_GET['name']]); $members = Member::get()->where(sprintf('"Name" = %s', Convert::raw2sql($_GET['name'], true))); ``` -[warning] -It is NOT good practice to "be sure" and convert the data passed to the functions above manually. This might -result in *double escaping* and alters the actually saved data (e.g. by adding slashes to your content). -[/warning] +> [!WARNING] +> It is NOT good practice to "be sure" and convert the data passed to the functions above manually. This might +> result in *double escaping* and alters the actually saved data (e.g. by adding slashes to your content). ### Manual escaping @@ -214,10 +213,9 @@ XSS (Cross-Site-Scripting). With some basic guidelines, you can ensure your outp displaying a blog post in HTML from a trusted author, or escaping a search parameter from an untrusted visitor before redisplaying it). -[notice] -Note: Silverstripe CMS templates do not remove tags, please use [strip_tags()](http://php.net/strip_tags) for this purpose -or [sanitize](http://htmlpurifier.org/) it correctly. -[/notice] +> [!WARNING] +> Note: Silverstripe CMS templates do not remove tags, please use [strip_tags()](http://php.net/strip_tags) for this purpose +> or [sanitize](http://htmlpurifier.org/) it correctly. See [http://shiflett.org/articles/foiling-cross-site-attacks](http://shiflett.org/articles/foiling-cross-site-attacks) for in-depth information about "Cross-Site-Scripting". @@ -343,10 +341,9 @@ class MyObject extends DataObject } ``` -[info] -If `$title` was a public property called `$Title`, it would also be casted the same way that the result of -`$getTitle()` is casted. -[/info] +> [!NOTE] +> If `$title` was a public property called `$Title`, it would also be casted the same way that the result of +> `$getTitle()` is casted. Template: @@ -369,23 +366,21 @@ template, you'll need to take care of casting and escaping yourself in PHP. The [Convert](api:SilverStripe\Core\Convert) class has utilities for this, mainly *Convert::raw2xml()* and *Convert::raw2att()* (which is also used by *XML* and *ATT* in template code). -[warning] -Most of the `Convert::raw2` methods accept arrays and do not affect array keys. -If you serialize your data, make sure to do that before you pass it to `Convert::raw2` methods. - -For example: - -```php -use SilverStripe\Core\Convert; - -// WRONG! -json_encode(Convert::raw2sql($request->getVar('multiselect'))); - -// Correct! -Convert::raw2sql(json_encode($request->getVar('multiselect'))); -``` - -[/warning] +> [!WARNING] +> Most of the `Convert::raw2` methods accept arrays and do not affect array keys. +> If you serialize your data, make sure to do that before you pass it to `Convert::raw2` methods. +> +> For example: +> +> ```php +> use SilverStripe\Core\Convert; +> +> // WRONG! +> json_encode(Convert::raw2sql($request->getVar('multiselect'))); +> +> // Correct! +> Convert::raw2sql(json_encode($request->getVar('multiselect'))); +> ``` PHP: @@ -818,10 +813,9 @@ SilverStripe\Core\Injector\Injector: TokenCookieSecure: true ``` -[info] -There is not currently an easy way to pass a `samesite` attribute value for setting this cookie - but you can set the -default value for the attribute for all cookies. See [the main cookies documentation](/developer_guides/cookies_and_sessions/cookies#samesite-attribute) for more information. -[/info] +> [!NOTE] +> There is not currently an easy way to pass a `samesite` attribute value for setting this cookie - but you can set the +> default value for the attribute for all cookies. See [the main cookies documentation](/developer_guides/cookies_and_sessions/cookies#samesite-attribute) for more information. For other cookies set by your application we should also ensure the users are provided with secure cookies by setting the "Secure" and "HTTPOnly" flags. These flags prevent them from being stolen by an attacker through JavaScript. diff --git a/en/02_Developer_Guides/10_Email/index.md b/en/02_Developer_Guides/10_Email/index.md index a933270ff..db93cf3b5 100644 --- a/en/02_Developer_Guides/10_Email/index.md +++ b/en/02_Developer_Guides/10_Email/index.md @@ -133,11 +133,10 @@ $email = Email::create($from, $to, $subject, $body); $email->send(); ``` -[info] -The default HTML template for emails is named `GenericEmail` and is located in `vendor/silverstripe/framework/templates/SilverStripe/Email/`. -To customise this template, copy it to the `app/templates/Email/` folder or use `setHTMLTemplate` when you create the -`Email` instance. -[/info] +> [!NOTE] +> The default HTML template for emails is named `GenericEmail` and is located in `vendor/silverstripe/framework/templates/SilverStripe/Email/`. +> To customise this template, copy it to the `app/templates/Email/` folder or use `setHTMLTemplate` when you create the +> `Email` instance. ### Templates @@ -173,10 +172,9 @@ if ($email->send()) { } ``` -[alert] -As we've added a new template file (`MyCustomEmail`) make sure you clear the Silverstripe CMS cache for your changes to -take affect. -[/alert] +> [!CAUTION] +> As we've added a new template file (`MyCustomEmail`) make sure you clear the Silverstripe CMS cache for your changes to +> take affect. #### Custom plain templates @@ -210,10 +208,9 @@ SilverStripe\Control\Email\Email: support@example.com: 'Support team' ``` -[alert] -Remember, setting a `from` address that doesn't come from your domain (such as the users email) will likely see your -email marked as spam. If you want to send from another address think about using the `setReplyTo` method. -[/alert] +> [!CAUTION] +> Remember, setting a `from` address that doesn't come from your domain (such as the users email) will likely see your +> email marked as spam. If you want to send from another address think about using the `setReplyTo` method. You will also have to remove the `SS_SEND_ALL_EMAILS_FROM` environment variable if it is present. @@ -271,9 +268,8 @@ $email = Email::create(/* ... */); $email->getSwiftMessage()->getHeaders()->addTextHeader('HeaderName', 'HeaderValue'); ``` -[info] -See this [Wikipedia](http://en.wikipedia.org/wiki/E-mail#Message_header) entry for a list of header names. -[/info] +> [!NOTE] +> See this [Wikipedia](http://en.wikipedia.org/wiki/E-mail#Message_header) entry for a list of header names. ## Disabling emails diff --git a/en/02_Developer_Guides/11_Integration/02_RSSFeed.md b/en/02_Developer_Guides/11_Integration/02_RSSFeed.md index 26e5c5f14..60ea67868 100644 --- a/en/02_Developer_Guides/11_Integration/02_RSSFeed.md +++ b/en/02_Developer_Guides/11_Integration/02_RSSFeed.md @@ -13,10 +13,9 @@ your current staff members, comments or any other custom [DataObject](api:Silver logical limitation here is that every item in the RSS-feed should be accessible through a URL on your website, so it's advisable to just create feeds from subclasses of [SiteTree](api:SilverStripe\CMS\Model\SiteTree). -[warning] -If you wish to generate an RSS feed that contains a [DataObject](api:SilverStripe\ORM\DataObject), ensure you define a `AbsoluteLink` method on -the object. -[/warning] +> [!WARNING] +> If you wish to generate an RSS feed that contains a [DataObject](api:SilverStripe\ORM\DataObject), ensure you define a `AbsoluteLink` method on +> the object. ## Usage @@ -101,9 +100,8 @@ class HomePageController extends PageController DataObjects can be rendered in the feed as well, however, since they aren't explicitly [SiteTree](api:SilverStripe\CMS\Model\SiteTree) subclasses we need to include a function `AbsoluteLink` to allow the RSS feed to link through to the item. -[info] -If the items are all displayed on a single page you may simply hard code the link to point to a particular page. -[/info] +> [!NOTE] +> If the items are all displayed on a single page you may simply hard code the link to point to a particular page. Take an example, we want to create an RSS feed of all the `Players` objects in our site. We make sure the `AbsoluteLink` method is defined and returns a string to the full website URL. @@ -217,9 +215,8 @@ class HomePage extends Page } ``` -[warning] -As we've added a new template (PlayersRss.ss) make sure you clear your Silverstripe CMS cache. -[/warning] +> [!WARNING] +> As we've added a new template (PlayersRss.ss) make sure you clear your Silverstripe CMS cache. ## API documentation diff --git a/en/02_Developer_Guides/11_Integration/How_Tos/Import_CSV_through_a_Controller.md b/en/02_Developer_Guides/11_Integration/How_Tos/Import_CSV_through_a_Controller.md index c009079a9..74773c0a5 100644 --- a/en/02_Developer_Guides/11_Integration/How_Tos/Import_CSV_through_a_Controller.md +++ b/en/02_Developer_Guides/11_Integration/How_Tos/Import_CSV_through_a_Controller.md @@ -81,7 +81,6 @@ class MyController extends Controller } ``` -[alert] -This interface is not secured, consider using [Permission::check()](api:SilverStripe\Security\Permission::check()) to limit the controller to users with certain -access rights. -[/alert] +> [!CAUTION] +> This interface is not secured, consider using [Permission::check()](api:SilverStripe\Security\Permission::check()) to limit the controller to users with certain +> access rights. diff --git a/en/02_Developer_Guides/12_Search/01_Searchcontext.md b/en/02_Developer_Guides/12_Search/01_Searchcontext.md index 4bd365b8b..41b6d801d 100644 --- a/en/02_Developer_Guides/12_Search/01_Searchcontext.md +++ b/en/02_Developer_Guides/12_Search/01_Searchcontext.md @@ -13,9 +13,8 @@ search parameters and an object class it acts on. The default output of a [SearchContext](api:SilverStripe\ORM\Search\SearchContext) is either a [SQLSelect](api:SilverStripe\ORM\Queries\SQLSelect) object for further refinement, or a [DataObject](api:SilverStripe\ORM\DataObject) instance. -[notice] -[SearchContext](api:SilverStripe\ORM\Search\SearchContext) is mainly used by [ModelAdmin](/developer_guides/customising_the_admin_interface/modeladmin), as it powers the [`DataObject::$searchable_fields` configuration](/developer_guides/model/scaffolding#searchable-fields). -[/notice] +> [!WARNING] +> [SearchContext](api:SilverStripe\ORM\Search\SearchContext) is mainly used by [ModelAdmin](/developer_guides/customising_the_admin_interface/modeladmin), as it powers the [`DataObject::$searchable_fields` configuration](/developer_guides/model/scaffolding#searchable-fields). ## Usage @@ -77,15 +76,11 @@ class MyDataObject extends DataObject } ``` -[notice] -See the [SearchFilter](../model/searchfilters) documentation for more information about filters to use such as the -`GreaterThanFilter`. -[/notice] +> [!WARNING] +> In case you need multiple contexts, consider name-spacing your request parameters by using `FieldList->namespace()` on +> the `$fields` constructor parameter. -[notice] -In case you need multiple contexts, consider name-spacing your request parameters by using `FieldList->namespace()` on -the `$fields` constructor parameter. -[/notice] +See the [SearchFilter](../model/searchfilters) documentation for more information about filters to use such as the `GreaterThanFilter`. ### Customising the general search field @@ -198,7 +193,7 @@ Another thing you can't forget is to check the name of the singleton you are usi to show the results of your custom search you need at least this content in your template, notice that Results.PaginationSummary(4) defines how many pages the search will show in the search results. something like: -**Next 1 2 *3* 4 5 … 558** +**Next 1 2 *3* 4 5 … 558** ```ss <% if $Results %> @@ -217,7 +212,7 @@ Results.PaginationSummary(4) defines how many pages the search will show in the <% if $Results.NotFirstPage %> <% end_if %> - + <% loop $Results.PaginationSummary(4) %> <% if $CurrentBool %> @@ -231,7 +226,7 @@ Results.PaginationSummary(4) defines how many pages the search will show in the <% end_if %> <% end_loop %> - + <% if $Results.NotLastPage %> <% end_if %> diff --git a/en/02_Developer_Guides/12_Search/02_FulltextSearch.md b/en/02_Developer_Guides/12_Search/02_FulltextSearch.md index 63256995e..aa33293e8 100644 --- a/en/02_Developer_Guides/12_Search/02_FulltextSearch.md +++ b/en/02_Developer_Guides/12_Search/02_FulltextSearch.md @@ -10,11 +10,10 @@ Fulltext search allows advanced search criteria for searching words within a tex Fulltext search can be achieved using the built-in [MySQLDatabase](api:SilverStripe\ORM\Connect\MySQLDatabase) class a more powerful wrapper for Fulltext search is provided through a module. -[notice] -See the [FulltextSearch Module](https://github.com/silverstripe-labs/silverstripe-fulltextsearch/). This module provides -a high level wrapper for running advanced search services such as Solr, Lucene or Sphinx in the backend rather than -`MySQL` search. -[/notice] +> [!WARNING] +> See the [FulltextSearch Module](https://github.com/silverstripe-labs/silverstripe-fulltextsearch/). This module provides +> a high level wrapper for running advanced search services such as Solr, Lucene or Sphinx in the backend rather than +> `MySQL` search. ## Adding fulltext support to `MySQLDatabase` @@ -40,11 +39,10 @@ class MyDataObject extends DataObject The [FulltextSearchable](api:SilverStripe\ORM\Search\FulltextSearchable) extension will add the correct `Fulltext` indexes to the data model. -[alert] -The [SearchForm](api:SilverStripe\CMS\Search\SearchForm) and [FulltextSearchable](api:SilverStripe\ORM\Search\FulltextSearchable) API's are currently hard coded to be specific to `Page` and `File` -records and cannot easily be adapted to include custom `DataObject` instances. To include your custom objects in the -default site search, have a look at those extensions and modify as required. -[/alert] +> [!CAUTION] +> The [SearchForm](api:SilverStripe\CMS\Search\SearchForm) and [FulltextSearchable](api:SilverStripe\ORM\Search\FulltextSearchable) API's are currently hard coded to be specific to `Page` and `File` +> records and cannot easily be adapted to include custom `DataObject` instances. To include your custom objects in the +> default site search, have a look at those extensions and modify as required. ### Fulltext filter diff --git a/en/02_Developer_Guides/13_i18n/index.md b/en/02_Developer_Guides/13_i18n/index.md index 6bffa7c00..35f650945 100644 --- a/en/02_Developer_Guides/13_i18n/index.md +++ b/en/02_Developer_Guides/13_i18n/index.md @@ -258,9 +258,8 @@ _t(__CLASS__ . '.GREETING', 'Welcome!'); ### Usage in template files -[hint] -The preferred template syntax has changed somewhat since [version 2.x](http://doc.silverstripe.org/framework/en/2.4/topics/i18n#usage-2). -[/hint] +> [!TIP] +> The preferred template syntax has changed somewhat since [version 2.x](http://doc.silverstripe.org/framework/en/2.4/topics/i18n#usage-2). In `.ss` template files, instead of `_t(params)` the syntax `<%t params %>` is used. The syntax for passing parameters to the function is quite different to the PHP version of the function. @@ -303,9 +302,8 @@ underscore function, and tell you about the created files and any possible entit If you want to run the text collector for just one module you can use the 'module' parameter: `http://localhost/dev/tasks/i18nTextCollectorTask/?module=cms` -[hint] -You'll need to install PHPUnit to run the text collector (see [testing-guide](/developer_guides/testing)). -[/hint] +> [!TIP] +> You'll need to install PHPUnit to run the text collector (see [testing-guide](/developer_guides/testing)). ## Module priority diff --git a/en/02_Developer_Guides/14_Files/03_File_Security.md b/en/02_Developer_Guides/14_Files/03_File_Security.md index 2f1b23ca1..8d66eb781 100644 --- a/en/02_Developer_Guides/14_Files/03_File_Security.md +++ b/en/02_Developer_Guides/14_Files/03_File_Security.md @@ -76,12 +76,11 @@ Most commonly this is through the "Access to Files section" permission. Custom implementations (e.g. APIs or custom file viewers) can have further restrictions in your project. -[warning] -When implementing your own `canView()` logic through [extensions](/developer_guides/extending/extensions), -existing unprotected files are not retroactively moved to the protected asset store. -While those new permissions are honoured in the CMS, protected files through custom `canView()` -can still be downloaded through a public URL until a `write()` operation is triggered on them. -[/warning] +> [!WARNING] +> When implementing your own `canView()` logic through [extensions](/developer_guides/extending/extensions), +> existing unprotected files are not retroactively moved to the protected asset store. +> While those new permissions are honoured in the CMS, protected files through custom `canView()` +> can still be downloaded through a public URL until a `write()` operation is triggered on them. ## Asset stores @@ -221,10 +220,9 @@ $object->SecretFile->protectFile(); $object->PublicFile->publishFile(); ``` -[notice] -One thing to note is that all variants of a single file will be treated as -a single entity for access control, so specific variants cannot be individually controlled. -[/notice] +> [!WARNING] +> One thing to note is that all variants of a single file will be treated as +> a single entity for access control, so specific variants cannot be individually controlled. ## How file access is protected diff --git a/en/02_Developer_Guides/14_Files/06_Allowed_file_types.md b/en/02_Developer_Guides/14_Files/06_Allowed_file_types.md index be040fadf..315304e53 100644 --- a/en/02_Developer_Guides/14_Files/06_Allowed_file_types.md +++ b/en/02_Developer_Guides/14_Files/06_Allowed_file_types.md @@ -32,9 +32,8 @@ Any file not included in this config, or in the default list of extensions, will any requests to the assets directory. Invalid files will be blocked regardless of whether they exist or not, and will not invoke any PHP processes. -[warning] -While SVG images are a popular format to display images on the web, they are not included in the file extension whitelist because they can contain arbitrary scripts that will be executed when the image is rendered in a browser. Allowing CMS users to upload SVG images would be a significant XSS risk. We strongly advise developers against whitelisting the `svg` file extension. -[/warning] +> [!WARNING] +> While SVG images are a popular format to display images on the web, they are not included in the file extension whitelist because they can contain arbitrary scripts that will be executed when the image is rendered in a browser. Allowing CMS users to upload SVG images would be a significant XSS risk. We strongly advise developers against whitelisting the `svg` file extension. You can also remove pre-existing entries from the whitelist by setting them to `false`. diff --git a/en/02_Developer_Guides/15_Customising_the_Admin_Interface/01_ModelAdmin.md b/en/02_Developer_Guides/15_Customising_the_Admin_Interface/01_ModelAdmin.md index bbd1afcfb..e93d1a40d 100644 --- a/en/02_Developer_Guides/15_Customising_the_Admin_Interface/01_ModelAdmin.md +++ b/en/02_Developer_Guides/15_Customising_the_Admin_Interface/01_ModelAdmin.md @@ -11,10 +11,9 @@ searchables list and edit views of [DataObject](api:SilverStripe\ORM\DataObject) It uses the framework's knowledge about the model to provide sensible defaults, allowing you to get started in a couple of lines of code, while still providing a solid base for customization. -[info] -The interface is mainly powered by the [GridField](api:SilverStripe\Forms\GridField\GridField) class ([documentation](../forms/field_types/gridfield)), which can -also be used in other areas of your application. -[/info] +> [!NOTE] +> The interface is mainly powered by the [GridField](api:SilverStripe\Forms\GridField\GridField) class ([documentation](../forms/field_types/gridfield)), which can +> also be used in other areas of your application. Let's assume we want to manage a simple product listing as a sample data model: A product can have a name, price, and a category. @@ -86,9 +85,8 @@ class MyAdmin extends ModelAdmin This will automatically add a new menu entry to the Silverstripe CMS UI entitled `My Product Admin` and logged in users will be able to upload and manage `Product` and `Category` instances through . -[alert] -After defining these classes, make sure you have rebuilt your Silverstripe CMS database and flushed your cache. -[/alert] +> [!CAUTION] +> After defining these classes, make sure you have rebuilt your Silverstripe CMS database and flushed your cache. ## Defining the `ModelAdmin` models @@ -146,6 +144,12 @@ class MyAdmin extends ModelAdmin As of Silverstripe CMS 4.12.0 it is trivial to get links to the edit form for managed records. +> [!NOTE] +> The [getLinkForModelClass()](api:SilverStripe\Admin\ModelAdmin::getLinkForModelClass()) method returns a link +> for the first tab defined for that class. If you have multiple tabs for a given class (as in the example above) +> it is better to use [getLinkForModelTab()](api:SilverStripe\Admin\ModelAdmin::getLinkForModelTab()) which will +> give you a link for the specific tab you pass in. + ```php $admin = MyAdmin::singleton(); if ($admin->isManagedModel(Product::class)) { @@ -158,18 +162,10 @@ if ($admin->isManagedModel(Product::class)) { $tabLink = $admin->getLinkForModelTab('product-category'); ``` -[info] -The [getLinkForModelClass()](api:SilverStripe\Admin\ModelAdmin::getLinkForModelClass()) method returns a link -for the first tab defined for that class. If you have multiple tabs for a given class (as in the example above) -it is better to use [getLinkForModelTab()](api:SilverStripe\Admin\ModelAdmin::getLinkForModelTab()) which will -give you a link for the specific tab you pass in. -[/info] - -[hint] -If you want `getLinkForModelClass()` to return the link for a specific tab, you can override the -[getModelTabForModelClass()](api:SilverStripe\Admin\ModelAdmin::getModelTabForModelClass()) method -for your `ModelAdmin` subclass. -[/hint] +> [!TIP] +> If you want `getLinkForModelClass()` to return the link for a specific tab, you can override the +> [getModelTabForModelClass()](api:SilverStripe\Admin\ModelAdmin::getModelTabForModelClass()) method +> for your `ModelAdmin` subclass. You can also use the new [CMSEditLinkExtension](api:SilverStripe\Admin\CMSEditLinkExtension) to provide a `CMSEditLink()` method on the record - see [Managing Records](../model/managing_records#getting-an-edit-link). @@ -179,9 +175,8 @@ Each new `ModelAdmin` subclass creates its' own [permission code](../security), `CMS_ACCESS_MyAdmin`. Users with access to the Admin UI will need to have this permission assigned through `admin/security/` or have the `ADMIN` permission code in order to gain access to the controller. -[notice] -For more information on the security and permission system see the [Security Documentation](../security) -[/notice] +> [!WARNING] +> For more information on the security and permission system see the [Security Documentation](../security) The [DataObject](api:SilverStripe\ORM\DataObject) API has more granular permission control, which is enforced in [ModelAdmin](api:SilverStripe\Admin\ModelAdmin) by default. Available checks are `canEdit()`, `canCreate()`, `canView()` and `canDelete()`. Models check for administrator @@ -265,9 +260,8 @@ class Product extends DataObject } ``` -[hint] -[SearchContext](../search/searchcontext) documentation has more information on providing the search functionality. -[/hint] +> [!TIP] +> [SearchContext](../search/searchcontext) documentation has more information on providing the search functionality. ## Displaying results @@ -392,10 +386,9 @@ If you wish to provided a tailored esperience for CMS users, you can directly in Extensions applied to a ModelAdmin can also use the `updateGridField` and `updateGridFieldConfig` hooks. -[hint] -`getGridField()`, `getGridFieldConfig()`, `updateGridField` and `updateGridFieldConfig` are only available on -Silverstripe CMS 4.6 and above. -[/hint] +> [!TIP] +> `getGridField()`, `getGridFieldConfig()`, `updateGridField` and `updateGridFieldConfig` are only available on +> Silverstripe CMS 4.6 and above. To alter how the results are displayed (via [GridField](api:SilverStripe\Forms\GridField\GridField)), you can also overload the `getEditForm()` method. For example, to add a new component. diff --git a/en/02_Developer_Guides/15_Customising_the_Admin_Interface/02_CMS_Architecture.md b/en/02_Developer_Guides/15_Customising_the_Admin_Interface/02_CMS_Architecture.md index 0f8c49068..2a4cc6d31 100644 --- a/en/02_Developer_Guides/15_Customising_the_Admin_Interface/02_CMS_Architecture.md +++ b/en/02_Developer_Guides/15_Customising_the_Admin_Interface/02_CMS_Architecture.md @@ -249,11 +249,10 @@ correctly configured form. ## JavaScript through jQuery.Entwine -[notice] -The following documentation regarding Entwine does not apply to React components or sections powered by React. -If you're developing new functionality in React powered sections please refer to -[ReactJS in Silverstripe CMS](./How_Tos/Extend_CMS_Interface.md#reactjs-in-silverstripe). -[/notice] +> [!WARNING] +> The following documentation regarding Entwine does not apply to React components or sections powered by React. +> If you're developing new functionality in React powered sections please refer to +> [ReactJS in Silverstripe CMS](./How_Tos/Extend_CMS_Interface.md#reactjs-in-silverstripe). [jQuery.entwine](https://github.com/hafriedlander/jquery.entwine) is a thirdparty library which allows us to attach behaviour to DOM elements in a flexible and structured mannger. diff --git a/en/02_Developer_Guides/15_Customising_the_Admin_Interface/03_CMS_Layout.md b/en/02_Developer_Guides/15_Customising_the_Admin_Interface/03_CMS_Layout.md index 8c12cef34..93e17d259 100644 --- a/en/02_Developer_Guides/15_Customising_the_Admin_Interface/03_CMS_Layout.md +++ b/en/02_Developer_Guides/15_Customising_the_Admin_Interface/03_CMS_Layout.md @@ -5,11 +5,10 @@ summary: Add interactivity enhancements to the admin with Javascript # CMS layout -[notice] -The following documentation regarding JavaScript layouts does not apply to React components or sections powered by React. -If you're developing new functionality in React powered sections please refer to -[ReactJS in Silverstripe CMS](./how_tos/extend_cms_interface/#react-rendered-ui). -[/notice] +> [!WARNING] +> The following documentation regarding JavaScript layouts does not apply to React components or sections powered by React. +> If you're developing new functionality in React powered sections please refer to +> [ReactJS in Silverstripe CMS](./how_tos/extend_cms_interface/#react-rendered-ui). The CMS markup is structured into "panels", which are the base units containing interface components (or other panels), as declared by the class `cms-panel`. Panels can be made collapsible, and get the ability to be resized and aligned with @@ -37,17 +36,16 @@ This causes the framework to: to the layout manager) - trigger `redraw` on children which also cascades deeper into the hierarchy (this is framework activity) -[notice] -Caveat: `layout` is also triggered when a DOM element is replaced with AJAX in `LeftAndMain::handleAjaxResponse`. In -this case it is triggered on the parent of the element being replaced so jLayout has a chance to rebuild its algorithms. -Calling the top level `layout` is not enough as it will wrongly descend down the detached element's hierarchy. -[/notice] - -[notice] -Caveat: invocation order of the `redraws` is crucial here, generally going from innermost to outermost elements. For -example, the tab panels have be applied in the CMS form before the form itself is layouted with its sibling panels to -avoid incorrect dimensions. -[/notice] +> [!WARNING] +> There are some caveats to this: +> +> `layout` is also triggered when a DOM element is replaced with AJAX in `LeftAndMain::handleAjaxResponse`. In +> this case it is triggered on the parent of the element being replaced so jLayout has a chance to rebuild its algorithms. +> Calling the top level `layout` is not enough as it will wrongly descend down the detached element's hierarchy. +> +> The invocation order of the `redraws` is crucial here, generally going from innermost to outermost elements. For +> example, the tab panels have be applied in the CMS form before the form itself is layouted with its sibling panels to +> avoid incorrect dimensions. ![Layout variations](../../_images/cms-architecture.png) diff --git a/en/02_Developer_Guides/15_Customising_the_Admin_Interface/04_Preview.md b/en/02_Developer_Guides/15_Customising_the_Admin_Interface/04_Preview.md index 7c2a4c04f..f323a0d8c 100644 --- a/en/02_Developer_Guides/15_Customising_the_Admin_Interface/04_Preview.md +++ b/en/02_Developer_Guides/15_Customising_the_Admin_Interface/04_Preview.md @@ -61,37 +61,35 @@ The format for that situation is always the same, with increasing complexity if nesting `GridField`s. For the below examples it is assumed you aren't using nested `GridField`s. -[hint] -As of Silverstripe CMS 4.12.0, you can -[use CMSEditLinkExtension](/developer_guides/model/managing_records#getting-an-edit-link). - -```php -namespace App\Model; - -use App\Admin\MyModelAdmin; -use SilverStripe\Admin\CMSEditLinkExtension; -use SilverStripe\ORM\CMSPreviewable; -use SilverStripe\ORM\DataObject; - -class MyParentModel extends DataObject implements CMSPreviewable -{ - private static string $cms_edit_owner = MyModelAdmin::class; - - private static $extensions = [ - CMSEditLinkExtension::class, - ]; - - public function CMSEditLink() - { - // Get the value returned by the extension - return $this->extend('CMSEditLink')[0]; - } - - // ... -} -``` - -[/hint] +> [!TIP] +> As of Silverstripe CMS 4.12.0, you can +> [use CMSEditLinkExtension](/developer_guides/model/managing_records#getting-an-edit-link). +> +> ```php +> namespace App\Model; +> +> use App\Admin\MyModelAdmin; +> use SilverStripe\Admin\CMSEditLinkExtension; +> use SilverStripe\ORM\CMSPreviewable; +> use SilverStripe\ORM\DataObject; +> +> class MyParentModel extends DataObject implements CMSPreviewable +> { +> private static string $cms_edit_owner = MyModelAdmin::class; +> +> private static $extensions = [ +> CMSEditLinkExtension::class, +> ]; +> +> public function CMSEditLink() +> { +> // Get the value returned by the extension +> return $this->extend('CMSEditLink')[0]; +> } +> +> // ... +> } +> ``` #### GetMimeType @@ -212,9 +210,8 @@ Note that if you had set up this model to [act like a page](https://www.silverst you could simply `return $this->Link($action)`. In that case the new action would not need to be added to your `ModelAdmin`. -[warning] -Note: The `if (!$this->isInDB())` check below is important! Without this, the preview panel will redirect you to a 404 page when creating a new object. -[/warning] +> [!WARNING] +> Note: The `if (!$this->isInDB())` check below is important! Without this, the preview panel will redirect you to a 404 page when creating a new object. From Silverstripe CMS 4.12.0 onwards `ModelAdmin` provides methods for generating a link for the correct model: @@ -279,10 +276,9 @@ class Product extends DataObject implements CMSPreviewable } ``` -[notice] -If the `ModelAdmin` uses a tab name other than the class name and you're using a version -prior to 4.12.0, you'll have to pass that into `Link()` instead. -[/notice] +> [!WARNING] +> If the `ModelAdmin` uses a tab name other than the class name and you're using a version +> prior to 4.12.0, you'll have to pass that into `Link()` instead. The `CMSEditLink()` method is also very easy to implement, because the edit link used by `ModelAdmin` is predictable. @@ -426,58 +422,56 @@ class MyAdmin extends ModelAdmin } ``` -[hint] -If the CSS or JS you have added via [the Requirements API](/developer_guides/templates/requirements/#php-requirements-api) -aren't coming through, you may need to add `` and `` tags to the markup. It may not be appropriate to do this in -your main template (you don't want two `` tags on a page that includes the template), so you might need a preview wrapper -template, like so: - -```ss -<%-- themes/mytheme/templates/PreviewBase.ss --%> - - -<%-- head tag is needed for css to be injected --%> - -<%-- body tag is needed for javascript to be injected --%> - - <%-- these two divs are just here to comply with styling from the simple theme, replace them with your own theme markup --%> -
- $Preview -
- - -``` - -```php -// app/src/Admin/MyAdmin.php -namespace App\Admin; - -use SilverStripe\Admin\ModelAdmin; -use SilverStripe\View\ArrayData; -use SilverStripe\View\Requirements; -use SilverStripe\View\SSViewer; - -class MyAdmin extends ModelAdmin -{ - // ... - - public function cmsPreview() - { - // ... ommitted for brevity - - // Add in global css/js that would normally be added in the page base template (as needed) - Requirements::themedCSS('client/dist/css/style.css'); - // Render the preview content - $preview = $obj->forTemplate(); - // Wrap preview in proper html, body, etc so Requirements are used - $preview = SSViewer::create('PreviewBase')->process(ArrayData::create(['Preview' => $preview])); - - // ... ommitted for brevity - } -} -``` - -[/hint] +> [!TIP] +> If the CSS or JS you have added via [the Requirements API](/developer_guides/templates/requirements/#php-requirements-api) +> aren't coming through, you may need to add `` and `` tags to the markup. It may not be appropriate to do this in +> your main template (you don't want two `` tags on a page that includes the template), so you might need a preview wrapper +> template, like so: +> +> ```ss +> <%-- themes/mytheme/templates/PreviewBase.ss --%> +> +> +> <%-- head tag is needed for css to be injected --%> +> +> <%-- body tag is needed for javascript to be injected --%> +> +> <%-- these two divs are just here to comply with styling from the simple theme, replace them with your own theme markup --%> +>
+> $Preview +>
+> +> +> ``` +> +> ```php +> // app/src/Admin/MyAdmin.php +> namespace App\Admin; +> +> use SilverStripe\Admin\ModelAdmin; +> use SilverStripe\View\ArrayData; +> use SilverStripe\View\Requirements; +> use SilverStripe\View\SSViewer; +> +> class MyAdmin extends ModelAdmin +> { +> // ... +> +> public function cmsPreview() +> { +> // ... ommitted for brevity +> +> // Add in global css/js that would normally be added in the page base template (as needed) +> Requirements::themedCSS('client/dist/css/style.css'); +> // Render the preview content +> $preview = $obj->forTemplate(); +> // Wrap preview in proper html, body, etc so Requirements are used +> $preview = SSViewer::create('PreviewBase')->process(ArrayData::create(['Preview' => $preview])); +> +> // ... ommitted for brevity +> } +> } +> ``` ### Enabling preview for `DataObject` models which belong to a page @@ -809,13 +803,12 @@ internal states of the layout. You can reach it by calling: $('.cms-container').entwine('.ss').getLayoutOptions().mode; ``` -[notice] -Caveat: the `.preview-mode-selector` appears twice, once in the preview and -second time in the CMS actions area as `#preview-mode-dropdown-in-cms`. This is -done because the user should still have access to the mode selector even if -preview is not visible. Currently CMS Actions are a separate area to the preview -option selectors, even if they try to appear as one horizontal bar. -[/notice] +> [!WARNING] +> Caveat: the `.preview-mode-selector` appears twice, once in the preview and +> second time in the CMS actions area as `#preview-mode-dropdown-in-cms`. This is +> done because the user should still have access to the mode selector even if +> preview is not visible. Currently CMS Actions are a separate area to the preview +> option selectors, even if they try to appear as one horizontal bar. ### Preview API diff --git a/en/02_Developer_Guides/15_Customising_the_Admin_Interface/06_Javascript_Development.md b/en/02_Developer_Guides/15_Customising_the_Admin_Interface/06_Javascript_Development.md index ba8846100..3645ab581 100644 --- a/en/02_Developer_Guides/15_Customising_the_Admin_Interface/06_Javascript_Development.md +++ b/en/02_Developer_Guides/15_Customising_the_Admin_Interface/06_Javascript_Development.md @@ -25,11 +25,10 @@ in a browser. This transpiling can be done using a variety of toolchains, but th - [Babel](http://babeljs.io) (ES6 transpiler) - [Webpack](http://webpack.js.org) (Module bundler) -[notice] -The following documentation regarding jQuery, jQueryUI and Entwine does not apply to React components or sections powered by React. -If you're developing new functionality in React powered sections please refer to -[ReactJS, Redux, and GraphQL](./reactjs_redux_and_graphql). -[/notice] +> [!WARNING] +> The following documentation regarding jQuery, jQueryUI and Entwine does not apply to React components or sections powered by React. +> If you're developing new functionality in React powered sections please refer to +> [ReactJS, Redux, and GraphQL](./reactjs_redux_and_graphql). ## jQuery, jQuery UI and jQuery.Entwine: our libraries of choice diff --git a/en/02_Developer_Guides/15_Customising_the_Admin_Interface/07_ReactJS_Redux_and_GraphQL.md b/en/02_Developer_Guides/15_Customising_the_Admin_Interface/07_ReactJS_Redux_and_GraphQL.md index 1cd2e50e0..aab148dbf 100644 --- a/en/02_Developer_Guides/15_Customising_the_Admin_Interface/07_ReactJS_Redux_and_GraphQL.md +++ b/en/02_Developer_Guides/15_Customising_the_Admin_Interface/07_ReactJS_Redux_and_GraphQL.md @@ -19,12 +19,11 @@ There are some several members of this ecosystem that all work together to provi All of these pillars of the frontend application can be customised, giving you more control over how the admin interface looks, feels, and behaves. -[alert] -These technologies underpin the future of Silverstripe CMS development, but their current implementation is -*experimental*. Our APIs are not expected to change drastically between releases, but they are excluded from -our [semantic versioning](https://semver.org) commitments for the time being. Any breaking changes will be -clearly signalled in release notes. -[/alert] +> [!CAUTION] +> These technologies underpin the future of Silverstripe CMS development, but their current implementation is +> *experimental*. Our APIs are not expected to change drastically between releases, but they are excluded from +> our [semantic versioning](https://semver.org) commitments for the time being. Any breaking changes will be +> clearly signalled in release notes. First, a brief summary of what each of these are: @@ -243,6 +242,9 @@ const addLoggingMiddleware = (next) => (error) => { If you've created a module using React, it's a good idea to afford other developers an API to enhance those components, forms, and state. To do that, simply register them with `Injector`. +> [!WARNING] +> Because of the unique structure of the `form` middleware, you cannot register new services to `Injector.form`. + ```js // my-public-module/js/main.js import Injector from 'lib/Injector'; @@ -257,15 +259,10 @@ Services can then be fetched using their respective `.get()` methods. const MyComponent = Injector.component.get('MyComponent'); ``` -[notice] -Because of the unique structure of the `form` middleware, you cannot register new services to `Injector.form`. -[/notice] - -[alert] -Overwriting components by calling `register()` multiple times for the same -service name is discouraged, and will throw an error. Should you really need to do this, -you can pass `{ force: true }` as the third argument to the `register()` function. -[/alert] +> [!CAUTION] +> Overwriting components by calling `register()` multiple times for the same +> service name is discouraged, and will throw an error. Should you really need to do this, +> you can pass `{ force: true }` as the third argument to the `register()` function. ### Transforming services using middleware @@ -346,14 +343,12 @@ Injector.transform( ); ``` -[info] -This flag can only be used once per transformation. -The following are not allowed: - -- `{ before: ['*', 'something-else'] }` -- `{ after: '*', before: 'something-else' }` - -[/info] +> [!NOTE] +> This flag can only be used once per transformation. +> The following are not allowed: +> +> - `{ before: ['*', 'something-else'] }` +> - `{ after: '*', before: 'something-else' }` ### Injector context @@ -605,6 +600,9 @@ Injector.transform( ); ``` +> [!WARNING] +> It is critical that you end series of mutation calls with `getState()`. + The `alterSchema()` function takes a callback, with an instance of `FormStateManager` (`form` in the above example) as a parameter. `FormStateMangaer` allows you to declaratively update the form schema API using several helper methods, including: @@ -617,14 +615,9 @@ API using several helper methods, including: - `addFieldClass(fieldName:string, cssClassName:string)` - `removeFieldClass(fieldName:string, cssClassName:string)` -[info] -For a complete list of props that are available to update on a `Field` object, -see -[/info] - -[notice] -It is critical that you end series of mutation calls with `getState()`. -[/notice] +> [!NOTE] +> For a complete list of props that are available to update on a `Field` object, +> see In addition to mutation methods, several readonly methods are available on `FormSchemaManager` to read the current form state, including: @@ -936,9 +929,8 @@ SilverStripe\GraphQL\Manager: name: readNotes ``` -[hint] -GraphQL v3 uses the first part of the model class's namespace in the default query/mutation names - so with a class `App\Model\Note` the default read operation would be `readAppNotes`. The example above has overridden the default name to keep it consistent with GraphQL v4 behaviour. -[/hint] +> [!TIP] +> GraphQL v3 uses the first part of the model class's namespace in the default query/mutation names - so with a class `App\Model\Note` the default read operation would be `readAppNotes`. The example above has overridden the default name to keep it consistent with GraphQL v4 behaviour. #### Define the app @@ -1071,22 +1063,21 @@ Dynamic GraphQL queries are generated by populating pre-baked templates with spe In this example, we're using the `READ` template, which needs to know the plural name of the object (e.g. `READ` with `Notes` makes a `readNotes` query), whether pagination is activated, and which fields you want to query. -[hint] -For simplicity, we're not querying any relations or otherwise nested data here. If we had, for example, a `foo` relation with a `title` field and this was exposed in the schema, we would need to add it to the fields array like this: - -```js -const query = { - // ... - fields: [ - 'foo', [ - 'title', - ] - ], -}; -``` - -You might instinctively try to use JSON object notation for this instead, but that won't work. -[/hint] +> [!TIP] +> For simplicity, we're not querying any relations or otherwise nested data here. If we had, for example, a `foo` relation with a `title` field and this was exposed in the schema, we would need to add it to the fields array like this: +> +> ```js +> const query = { +> // ... +> fields: [ +> 'foo', [ +> 'title', +> ] +> ], +> }; +> ``` +> +> You might instinctively try to use JSON object notation for this instead, but that won't work. #### Register all the things @@ -1108,18 +1099,16 @@ const registerDependencies = () => { export default registerDependencies; ``` -[hint] -If you have a lot of components or queries to add, you can use `registerMany` instead: - -```js -Injector.component.registerMany({ - NotesList, - NotesListItem, - // ...etc -}); -``` - -[/hint] +> [!TIP] +> If you have a lot of components or queries to add, you can use `registerMany` instead: +> +> ```js +> Injector.component.registerMany({ +> NotesList, +> NotesListItem, +> // ...etc +> }); +> ``` We use `Injector.query.register()` to register our `readNotes` query so that other projects can extend it. @@ -1267,9 +1256,8 @@ SilverStripe\GraphQL\Manager: Let's first update the `NotesListItem` to contain our new field. -[notice] -Note that we're overriding the entire `NotesListItem` component. This is the main reason we broke the original list up into smaller components. -[/notice] +> [!WARNING] +> Note that we're overriding the entire `NotesListItem` component. This is the main reason we broke the original list up into smaller components. ```js // app/client/src/transformNotesListItem.js @@ -1368,10 +1356,9 @@ Injector.transform( ); ``` -[hint] -This transformation could either be transpiled as-is, or if you have other JavaScript to include in this module you might want to export it as a function and call it from some entry point. -Don't forget to add the transpiled result to the CMS e.g. via the `SilverStripe\Admin\LeftAndMain.extra_requirements_javascript` configuration property. -[/hint] +> [!TIP] +> This transformation could either be transpiled as-is, or if you have other JavaScript to include in this module you might want to export it as a function and call it from some entry point. +> Don't forget to add the transpiled result to the CMS e.g. via the `SilverStripe\Admin\LeftAndMain.extra_requirements_javascript` configuration property. ### Creating extensible mutations @@ -1399,9 +1386,8 @@ const AddForm = ({ onAdd }) => { export default AddForm; ``` -[info] -Because this isn't a full react tutorial, we've avoided the complexity of ensuring the list gets updated when we add an item to the form. You'll have to refresh the page to see your note after adding it. -[/info] +> [!NOTE] +> Because this isn't a full react tutorial, we've avoided the complexity of ensuring the list gets updated when we add an item to the form. You'll have to refresh the page to see your note after adding it. And we'll inject that component into our `App` container. @@ -1456,9 +1442,8 @@ const mutation = { export default mutation; ``` -[notice] -With GraphQL v3, the field names in the input object have to start with capital letters, and the input *type* can't easily be overridden - it's always the first part of your namespace, then the class name, then "CreateInputType". So assuming your model's fully qualified classname is `App\Model\Note`, the input type is `AppNoteCreateInputType`. -[/notice] +> [!WARNING] +> With GraphQL v3, the field names in the input object have to start with capital letters, and the input *type* can't easily be overridden - it's always the first part of your namespace, then the class name, then "CreateInputType". So assuming your model's fully qualified classname is `App\Model\Note`, the input type is `AppNoteCreateInputType`. It looks like a lot of code, but if you're familiar with Apollo mutations, this is pretty standard. The supplied `mutate()` function gets mapped to a prop - in this case `onAdd`, which the `AddForm` component is configured to invoke. We've also supplied the `singularName` as well as the template `CREATE` for the `createNote` scaffolded mutation. @@ -1491,9 +1476,8 @@ SilverStripe\GraphQL\Manager: create: true ``` -[notice] -Unlike with the read query, the injector isn't able to handle mutations with custom names. -[/notice] +> [!WARNING] +> Unlike with the read query, the injector isn't able to handle mutations with custom names. Lastly, let's just register all this with `Injector`. diff --git a/en/02_Developer_Guides/15_Customising_the_Admin_Interface/How_Tos/CMS_Alternating_Button.md b/en/02_Developer_Guides/15_Customising_the_Admin_Interface/How_Tos/CMS_Alternating_Button.md index 7cfe2afb2..ccae7505e 100644 --- a/en/02_Developer_Guides/15_Customising_the_Admin_Interface/How_Tos/CMS_Alternating_Button.md +++ b/en/02_Developer_Guides/15_Customising_the_Admin_Interface/How_Tos/CMS_Alternating_Button.md @@ -90,11 +90,10 @@ class MyObject extends DataObject ## Frontend support -[notice] -The following documentation regarding jQuery, jQueryUI and Entwine does not apply to React components or sections powered by React. -If you're developing new functionality in React powered sections please refer to -[ReactJS in Silverstripe CMS](./extend_cms_interface.md#reactjs-in-silverstripe). -[/notice] +> [!WARNING] +> The following documentation regarding jQuery, jQueryUI and Entwine does not apply to React components or sections powered by React. +> If you're developing new functionality in React powered sections please refer to +> [ReactJS in Silverstripe CMS](./extend_cms_interface.md#reactjs-in-silverstripe). As with the *Save* and *Save & publish* buttons, you might want to add some scripted reactions to user actions on the frontend. You can affect the state of the button through the jQuery UI calls. diff --git a/en/02_Developer_Guides/15_Customising_the_Admin_Interface/How_Tos/Customise_Site_Reports.md b/en/02_Developer_Guides/15_Customising_the_Admin_Interface/How_Tos/Customise_Site_Reports.md index 55d1f3738..f7c2e5ca7 100644 --- a/en/02_Developer_Guides/15_Customising_the_Admin_Interface/How_Tos/Customise_Site_Reports.md +++ b/en/02_Developer_Guides/15_Customising_the_Admin_Interface/How_Tos/Customise_Site_Reports.md @@ -23,9 +23,8 @@ SilverStripe\Reports\Report: limit_count_in_overview: 500 ``` -[notice] -Note that some reports may have overridden the `getCount` method, and for those reports this may not apply. -[/notice] +> [!WARNING] +> Note that some reports may have overridden the `getCount` method, and for those reports this may not apply. ## Default reports diff --git a/en/02_Developer_Guides/15_Customising_the_Admin_Interface/How_Tos/Extend_CMS_Interface.md b/en/02_Developer_Guides/15_Customising_the_Admin_Interface/How_Tos/Extend_CMS_Interface.md index b2fa31d21..e1fea0f9b 100644 --- a/en/02_Developer_Guides/15_Customising_the_Admin_Interface/How_Tos/Extend_CMS_Interface.md +++ b/en/02_Developer_Guides/15_Customising_the_Admin_Interface/How_Tos/Extend_CMS_Interface.md @@ -227,9 +227,8 @@ We can also easily create new drop-up menus by defining new tabs within the $fields->addFieldToTab('ActionMenus.MyDropUp', FormAction::create('minor', 'Minor action in a new drop-up')); ``` -[hint] -Empty tabs will be automatically removed from the `FieldList` to prevent clutter. -[/hint] +> [!TIP] +> Empty tabs will be automatically removed from the `FieldList` to prevent clutter. To make the actions more user-friendly you can also use alternating buttons as detailed in the [CMS Alternating Button](cms_alternating_button) diff --git a/en/02_Developer_Guides/16_Execution_Pipeline/01_Flushable.md b/en/02_Developer_Guides/16_Execution_Pipeline/01_Flushable.md index 0a96df5ba..7423b5aa8 100644 --- a/en/02_Developer_Guides/16_Execution_Pipeline/01_Flushable.md +++ b/en/02_Developer_Guides/16_Execution_Pipeline/01_Flushable.md @@ -11,11 +11,10 @@ Allows a class to define it's own flush functionality, which is triggered when ` [FlushMiddleware](api:SilverStripe\Control\Middleware\FlushMiddleware) is run before a request is made, calling `flush()` statically on all implementors of [Flushable](api:SilverStripe\Core\Flushable). -[notice] -Flushable implementers might also be triggered automatically on deploy if you have `SS_FLUSH_ON_DEPLOY` [environment -variable](../configuration/environment_variables) defined. In that case even if you don't manually pass `flush=1` parameter, the first request after deploy -will still be calling `Flushable::flush` on those entities. -[/notice] +> [!WARNING] +> Flushable implementers might also be triggered automatically on deploy if you have `SS_FLUSH_ON_DEPLOY` [environment +> variable](../configuration/environment_variables) defined. In that case even if you don't manually pass `flush=1` parameter, the first request after deploy +> will still be calling `Flushable::flush` on those entities. ## Usage diff --git a/en/02_Developer_Guides/17_CLI/index.md b/en/02_Developer_Guides/17_CLI/index.md index b4a9514ce..770e6d534 100644 --- a/en/02_Developer_Guides/17_CLI/index.md +++ b/en/02_Developer_Guides/17_CLI/index.md @@ -19,21 +19,19 @@ cd your-webroot/ php vendor/silverstripe/framework/cli-script.php dev/build ``` -[notice] -Your command line PHP version is likely to use a different configuration as your webserver (run `php -i` to find out -more). This can be a good thing, your CLI can be configured to use higher memory limits than you would want your website -to have. -[/notice] +> [!WARNING] +> Your command line PHP version is likely to use a different configuration as your webserver (run `php -i` to find out +> more). This can be a good thing, your CLI can be configured to use higher memory limits than you would want your website +> to have. ## Sake - Silverstripe CMS make Sake is a simple wrapper around `cli-script.php`. It also tries to detect which `php` executable to use if more than one are available. It is accessible via `vendor/bin/sake`. -[info] -If you are using a Debian server: Check you have the php-cli package installed for sake to work. If you get an error -when running the command PHP -v, then you may not have php-cli installed so sake won't work. -[/info] +> [!NOTE] +> If you are using a Debian server: Check you have the php-cli package installed for sake to work. If you get an error +> when running the command PHP -v, then you may not have php-cli installed so sake won't work. ### Installation @@ -44,9 +42,8 @@ cd your-webroot/ sudo ./vendor/bin/sake installsake ``` -[warning] -This currently only works on UNIX like systems, not on Windows. -[/warning] +> [!WARNING] +> This currently only works on UNIX like systems, not on Windows. ### Configuration @@ -78,10 +75,9 @@ sake dev/ sake dev/build "flush=1" ``` -[alert] -You have to run "sake" with the same system user that runs your web server, -otherwise "flush" won't be able to clean the cache properly. -[/alert] +> [!CAUTION] +> You have to run "sake" with the same system user that runs your web server, +> otherwise "flush" won't be able to clean the cache properly. It can also be handy if you have a long running script.. @@ -146,9 +142,8 @@ sake -start my_process sake -stop my_process ``` -[notice] -`sake` stores `pid` and log files in the site root directory. -[/notice] +> [!WARNING] +> `sake` stores `pid` and log files in the site root directory. ## Arguments diff --git a/en/02_Developer_Guides/18_Cookies_And_Sessions/01_Cookies.md b/en/02_Developer_Guides/18_Cookies_And_Sessions/01_Cookies.md index 5154e3798..41545bf0b 100644 --- a/en/02_Developer_Guides/18_Cookies_And_Sessions/01_Cookies.md +++ b/en/02_Developer_Guides/18_Cookies_And_Sessions/01_Cookies.md @@ -28,9 +28,8 @@ Cookie::set($name, $value, $expiry = 90, $path = null, $domain = null, $secure = // Cookie::set('MyApplicationPreference', 'Yes'); ``` -[info] -To set a cookie for less than 1 day, you can assign an `$expiry` value that is lower than 1. e.g. `Cookie::set('name', 'value', $expiry = 0.5);` will set a cookie for 12 hours. -[/info] +> [!NOTE] +> To set a cookie for less than 1 day, you can assign an `$expiry` value that is lower than 1. e.g. `Cookie::set('name', 'value', $expiry = 0.5);` will set a cookie for 12 hours. ### Get @@ -63,9 +62,8 @@ SilverStripe\Control\Cookie: default_samesite: 'Strict' ``` -[info] -Note that this *doesn't* apply for the session cookie, which is handled separately. See [Sessions](/developer_guides/cookies_and_sessions/sessions#samesite-attribute). -[/info] +> [!NOTE] +> Note that this *doesn't* apply for the session cookie, which is handled separately. See [Sessions](/developer_guides/cookies_and_sessions/sessions#samesite-attribute). ## Cookie_Backend diff --git a/en/02_Developer_Guides/19_GraphQL/01_getting_started/01_activating_the_server.md b/en/02_Developer_Guides/19_GraphQL/01_getting_started/01_activating_the_server.md index f46296dc9..574b1ab31 100644 --- a/en/02_Developer_Guides/19_GraphQL/01_getting_started/01_activating_the_server.md +++ b/en/02_Developer_Guides/19_GraphQL/01_getting_started/01_activating_the_server.md @@ -8,11 +8,10 @@ icon: rocket [CHILDREN asList] -[info] -You are viewing docs for silverstripe/graphql 4.x. -If you are using 3.x, documentation can be found -[in the GitHub repository](https://github.com/silverstripe/silverstripe-graphql/tree/3) -[/info] +> [!NOTE] +> You are viewing docs for silverstripe/graphql 4.x. +> If you are using 3.x, documentation can be found +> [in the GitHub repository](https://github.com/silverstripe/silverstripe-graphql/tree/3) ## Activating the default GraphQL server @@ -27,10 +26,9 @@ in the user space (e.g. `/graphql`) - i.e. your custom schema, while `admin` ref GraphQL server used by CMS modules (`admin/graphql`). You can also [set up a new schema server](#setting-up-a-custom-graphql-server) if you wish. -[info] -The word "server" here refers to a route with its own isolated GraphQL schema. It does -not refer to a web server. -[/info] +> [!NOTE] +> The word "server" here refers to a route with its own isolated GraphQL schema. It does +> not refer to a web server. By default, `silverstripe/graphql` does not route any GraphQL servers. To activate the default, public-facing GraphQL server that ships with the module, just add a rule to [`Director`](api:SilverStripe\Control\Director). diff --git a/en/02_Developer_Guides/19_GraphQL/01_getting_started/02_configuring_your_schema.md b/en/02_Developer_Guides/19_GraphQL/01_getting_started/02_configuring_your_schema.md index 364a48583..0ac609bc5 100644 --- a/en/02_Developer_Guides/19_GraphQL/01_getting_started/02_configuring_your_schema.md +++ b/en/02_Developer_Guides/19_GraphQL/01_getting_started/02_configuring_your_schema.md @@ -8,11 +8,10 @@ icon: code [CHILDREN asList] -[info] -You are viewing docs for silverstripe/graphql 4.x. -If you are using 3.x, documentation can be found -[in the GitHub repository](https://github.com/silverstripe/silverstripe-graphql/tree/3) -[/info] +> [!NOTE] +> You are viewing docs for silverstripe/graphql 4.x. +> If you are using 3.x, documentation can be found +> [in the GitHub repository](https://github.com/silverstripe/silverstripe-graphql/tree/3) ## Configuring your schema @@ -71,11 +70,10 @@ have to `flush=1` every time you make a schema update, which will slow down your It is recommended that you store your schema YAML **outside of the _config directory** to increase performance and remove the need for flushing when you [build your schema](building_the_schema). -[notice] -This doesn't mean there is never a need to `flush=1` when building your schema. If you were to add a new -schema, make a change to the value of this `src` attribute, or create new PHP classes, those are still -standard config changes which won't take effect without a flush. -[/notice] +> [!WARNING] +> This doesn't mean there is never a need to `flush=1` when building your schema. If you were to add a new +> schema, make a change to the value of this `src` attribute, or create new PHP classes, those are still +> standard config changes which won't take effect without a flush. We can do this by adding a `src` key to our `app/_config/graphql.yml` schema definition that maps to a directory relative to the project root. @@ -92,22 +90,20 @@ SilverStripe\GraphQL\Schema\Schema: Your `src` must be an array. This allows further source files to be merged into your schema. This feature can be use to extend the schema of third party modules. -[info] -Your directory can also be relative to a module reference, e.g. `somevendor/somemodule: _graphql`: - -```yml -# app/_config/graphql.yml -SilverStripe\GraphQL\Schema\Schema: - schemas: - default: - src: - - app/_graphql - - module/_graphql - # The next line would map to `vendor/somevendor/somemodule/_graphql` - - 'somevendor/somemodule: _graphql' -``` - -[/info] +> [!NOTE] +> Your directory can also be relative to a module reference, e.g. `somevendor/somemodule: _graphql`: +> +> ```yml +> # app/_config/graphql.yml +> SilverStripe\GraphQL\Schema\Schema: +> schemas: +> default: +> src: +> - app/_graphql +> - module/_graphql +> # The next line would map to `vendor/somevendor/somemodule/_graphql` +> - 'somevendor/somemodule: _graphql' +> ``` Now, in the new `app/_graphql` folder, we can create YAML file definitions. @@ -189,10 +185,9 @@ be implicitly placed in the corresponding section of the schema - e.g. any confi added to a `.yml` file in `app/_graphql/config/` will be implicitly added to `SilverStripe\GraphQL\Schema\Schema.schemas.default.config`. -[hint] -The names of the actual files here do not matter. You could for example have a separate file -for each of your types, e.g. `app/_graphql/types/my-first-type.yml`. -[/hint] +> [!TIP] +> The names of the actual files here do not matter. You could for example have a separate file +> for each of your types, e.g. `app/_graphql/types/my-first-type.yml`. ```yml # app/_graphql/config/config.yml @@ -269,10 +264,9 @@ and [resolver discovery](../working_with_generic_types/resolver_discovery) secti Let's define a generic type for our GraphQL schema. -[info] -Generic types don't map to `DataObject` classes - they're useful for querying more 'generic' data (hence the name). -You'll learn more about adding DataObjects in [working with DataObjects](../working_with_DataObjects). -[/info] +> [!NOTE] +> Generic types don't map to `DataObject` classes - they're useful for querying more 'generic' data (hence the name). +> You'll learn more about adding DataObjects in [working with DataObjects](../working_with_DataObjects). ```yml # app/_graphql/types.yml @@ -302,10 +296,9 @@ To define a type as required (non-null), you add an exclamation mark: `String!` Often times, you may want to do both: `[String!]!` -[notice] -Look out for the footgun, here. Make sure your bracketed type is in quotes -(i.e. `'[String]'`, not `[String]`), otherwise it's valid YAML that will get parsed as an array! -[/notice] +> [!WARNING] +> Look out for the footgun, here. Make sure your bracketed type is in quotes +> (i.e. `'[String]'`, not `[String]`), otherwise it's valid YAML that will get parsed as an array! That's all there is to it! To learn how we can take this further, check out the [working with generic types](../working_with_generic_types) documentation. Otherwise, diff --git a/en/02_Developer_Guides/19_GraphQL/01_getting_started/03_building_the_schema.md b/en/02_Developer_Guides/19_GraphQL/01_getting_started/03_building_the_schema.md index 546c62dc4..5b9277660 100644 --- a/en/02_Developer_Guides/19_GraphQL/01_getting_started/03_building_the_schema.md +++ b/en/02_Developer_Guides/19_GraphQL/01_getting_started/03_building_the_schema.md @@ -8,11 +8,10 @@ icon: hammer [CHILDREN asList] -[info] -You are viewing docs for silverstripe/graphql 4.x. -If you are using 3.x, documentation can be found -[in the GitHub repository](https://github.com/silverstripe/silverstripe-graphql/tree/3) -[/info] +> [!NOTE] +> You are viewing docs for silverstripe/graphql 4.x. +> If you are using 3.x, documentation can be found +> [in the GitHub repository](https://github.com/silverstripe/silverstripe-graphql/tree/3) ## Building the schema @@ -32,10 +31,9 @@ whenever the schema definition changes, or a new schema definition is added. - Any time you run the `dev/build` command on your project. - `silverstripe/graphql` will attempt to generate your schema "on-demand" on the first GraphQL request *only* if it wasn’t already generated. -[warning] -Relying on the "on-demand" schema generation on the first GraphQL request requires some additional consideration. -See [deploying the schema](deploying_the_schema#on-demand). -[/warning] +> [!WARNING] +> Relying on the "on-demand" schema generation on the first GraphQL request requires some additional consideration. +> See [deploying the schema](deploying_the_schema#on-demand). #### Running `dev/graphql/build` @@ -47,16 +45,14 @@ This command takes an optional `schema` parameter. If you only want to generate (e.g. generate your custom schema, but not the CMS schema), you should pass in the name of the schema you want to build. -[info] -If you do not provide a `schema` parameter, the command will build all schemas. -[/info] +> [!NOTE] +> If you do not provide a `schema` parameter, the command will build all schemas. `vendor/bin/sake dev/graphql/build schema=default` -[info] -Most of the time, the name of your custom schema is `default`. If you're editing DataObjects -that are accessed with GraphQL in the CMS, you may have to rebuild the `admin` schema as well. -[/info] +> [!NOTE] +> Most of the time, the name of your custom schema is `default`. If you're editing DataObjects +> that are accessed with GraphQL in the CMS, you may have to rebuild the `admin` schema as well. Keep in mind that some of your changes will be in YAML in the `_config/` directory, which also requires a flush. @@ -113,10 +109,9 @@ those *are* meant to be accessible through your webserver. See [Tips and Tricks: Schema Introspection](tips_and_tricks#schema-introspection) to find out how to generate these files for your own schema. -[alert] -While it is safe for you to view these files, you should not manually alter them. If you need to make a change -to your GraphQL schema, you should [update the schema definition](configuring_your_schema) and rebuild your schema. -[/alert] +> [!CAUTION] +> While it is safe for you to view these files, you should not manually alter them. If you need to make a change +> to your GraphQL schema, you should [update the schema definition](configuring_your_schema) and rebuild your schema. ### Further reading diff --git a/en/02_Developer_Guides/19_GraphQL/01_getting_started/04_using_procedural_code.md b/en/02_Developer_Guides/19_GraphQL/01_getting_started/04_using_procedural_code.md index 17f77a575..3bb39a151 100644 --- a/en/02_Developer_Guides/19_GraphQL/01_getting_started/04_using_procedural_code.md +++ b/en/02_Developer_Guides/19_GraphQL/01_getting_started/04_using_procedural_code.md @@ -8,11 +8,10 @@ icon: tools [CHILDREN asList] -[info] -You are viewing docs for silverstripe/graphql 4.x. -If you are using 3.x, documentation can be found -[in the GitHub repository](https://github.com/silverstripe/silverstripe-graphql/tree/3) -[/info] +> [!NOTE] +> You are viewing docs for silverstripe/graphql 4.x. +> If you are using 3.x, documentation can be found +> [in the GitHub repository](https://github.com/silverstripe/silverstripe-graphql/tree/3) ## Building a schema with procedural code @@ -27,11 +26,10 @@ types is that they're dynamic. So the procedural API for schemas has to be prett Lastly, if you just prefer writing PHP to writing YAML, this is a good option, too. -[notice] -One thing you cannot do with the procedural API, though it may be tempting, is define resolvers -on the fly as closures. Resolvers must be static methods on a class, and are evaluated during -the schema build. -[/notice] +> [!WARNING] +> One thing you cannot do with the procedural API, though it may be tempting, is define resolvers +> on the fly as closures. Resolvers must be static methods on a class, and are evaluated during +> the schema build. ### Adding executable code diff --git a/en/02_Developer_Guides/19_GraphQL/01_getting_started/05_deploying_the_schema.md b/en/02_Developer_Guides/19_GraphQL/01_getting_started/05_deploying_the_schema.md index 387ac4bfa..a4408ae9c 100644 --- a/en/02_Developer_Guides/19_GraphQL/01_getting_started/05_deploying_the_schema.md +++ b/en/02_Developer_Guides/19_GraphQL/01_getting_started/05_deploying_the_schema.md @@ -8,11 +8,10 @@ icon: rocket [CHILDREN asList] -[info] -You are viewing docs for silverstripe/graphql 4.x. -If you are using 3.x, documentation can be found -[in the GitHub repository](https://github.com/silverstripe/silverstripe-graphql/tree/3) -[/info] +> [!NOTE] +> You are viewing docs for silverstripe/graphql 4.x. +> If you are using 3.x, documentation can be found +> [in the GitHub repository](https://github.com/silverstripe/silverstripe-graphql/tree/3) ## Deploying the schema @@ -30,9 +29,8 @@ A simplistic approach is to build the schema in your local development environme This approach has the advantage of being very simple, but it will pollute your commits with massive diffs for the generated code. -[notice] -Make sure you set your site to `live` mode and remove any `DEBUG_SCHEMA=1` from your `.env` file if it is there before generating the schema to be committed. -[/notice] +> [!WARNING] +> Make sure you set your site to `live` mode and remove any `DEBUG_SCHEMA=1` from your `.env` file if it is there before generating the schema to be committed. #### Explicitly build the schema during each deployment {#build-during-deployment} @@ -60,9 +58,8 @@ While benchmarking schema generation performance, we measured that a schema expo Our expectation is that on-demand schema generation will be performant for most projects with small or medium schemas. -[warning] -Note that with this approach you will need to remove or empty the `.graphql-generated/` and `public/_graphql/` folders on each server for each deployment that includes a change to the schema definition, or you risk having an outdated GraphQL schema. The "on-demand" schema generation does not detect changes to the schema definition. -[/warning] +> [!WARNING] +> Note that with this approach you will need to remove or empty the `.graphql-generated/` and `public/_graphql/` folders on each server for each deployment that includes a change to the schema definition, or you risk having an outdated GraphQL schema. The "on-demand" schema generation does not detect changes to the schema definition. #### Build the schema during/before deployment and share it across your servers {#multi-server-shared-dirs} diff --git a/en/02_Developer_Guides/19_GraphQL/01_getting_started/index.md b/en/02_Developer_Guides/19_GraphQL/01_getting_started/index.md index b313f7785..77f91549a 100644 --- a/en/02_Developer_Guides/19_GraphQL/01_getting_started/index.md +++ b/en/02_Developer_Guides/19_GraphQL/01_getting_started/index.md @@ -9,10 +9,9 @@ icon: rocket This section of the documentation will give you an overview of how to get a simple GraphQL API up and running with some `DataObject` content. -[info] -You are viewing docs for silverstripe/graphql 4.x. -If you are using 3.x, documentation can be found -[in the GitHub repository](https://github.com/silverstripe/silverstripe-graphql/tree/3) -[/info] +> [!NOTE] +> You are viewing docs for silverstripe/graphql 4.x. +> If you are using 3.x, documentation can be found +> [in the GitHub repository](https://github.com/silverstripe/silverstripe-graphql/tree/3) [CHILDREN] diff --git a/en/02_Developer_Guides/19_GraphQL/02_working_with_dataobjects/01_adding_dataobjects_to_the_schema.md b/en/02_Developer_Guides/19_GraphQL/02_working_with_dataobjects/01_adding_dataobjects_to_the_schema.md index 5d8525f28..53b8f4f66 100644 --- a/en/02_Developer_Guides/19_GraphQL/02_working_with_dataobjects/01_adding_dataobjects_to_the_schema.md +++ b/en/02_Developer_Guides/19_GraphQL/02_working_with_dataobjects/01_adding_dataobjects_to_the_schema.md @@ -7,11 +7,10 @@ summary: An overview of how the DataObject model can influence the creation of t [CHILDREN asList] -[info] -You are viewing docs for silverstripe/graphql 4.x. -If you are using 3.x, documentation can be found -[in the GitHub repository](https://github.com/silverstripe/silverstripe-graphql/tree/3) -[/info] +> [!NOTE] +> You are viewing docs for silverstripe/graphql 4.x. +> If you are using 3.x, documentation can be found +> [in the GitHub repository](https://github.com/silverstripe/silverstripe-graphql/tree/3) ## The `DataObject` model type @@ -49,10 +48,9 @@ Case in point, by supplying a value of `*` for `fields` , we're saying that we w on the `Page` class. This includes the first level of relationships, as defined on `has_one`, `has_many`, or `many_many`. -[notice] -Fields on relationships will not inherit the `*` fields selector, and will only expose their ID by default. -To add additional fields for those relationships you will need to add the corresponding `DataObject` model types. -[/notice] +> [!WARNING] +> Fields on relationships will not inherit the `*` fields selector, and will only expose their ID by default. +> To add additional fields for those relationships you will need to add the corresponding `DataObject` model types. The `*` value on `operations` tells the schema to create all available queries and mutations for the DataObject, including: @@ -71,6 +69,11 @@ Now we can access our schema on the default GraphQL endpoint, `/graphql`. Test it out! +> [!NOTE] +> Note the use of the default arguments on `date`. Fields created from `DBFields` +> generate their own default sets of arguments. For more information, see +> [DBFieldArgs](query_plugins#dbfieldargs). + **A query:** ```graphql @@ -95,16 +98,9 @@ query { } ``` -[info] -Note the use of the default arguments on `date`. Fields created from `DBFields` -generate their own default sets of arguments. For more information, see -[DBFieldArgs](query_plugins#dbfieldargs). -[/info] - -[info] -The `... on BlogPage` syntax is called an [inline fragment](https://graphql.org/learn/queries/#inline-fragments). -You can learn more about this syntax in the [Inheritance](../inheritance) section. -[/info] +> [!NOTE] +> The `... on BlogPage` syntax is called an [inline fragment](https://graphql.org/learn/queries/#inline-fragments). +> You can learn more about this syntax in the [Inheritance](../inheritance) section. **A mutation:** @@ -119,9 +115,8 @@ mutation { } ``` -[hint] -Did you get a permissions error? Make sure you're authenticated as someone with appropriate access. -[/hint] +> [!TIP] +> Did you get a permissions error? Make sure you're authenticated as someone with appropriate access. ### Configuring operations @@ -199,22 +194,20 @@ App\Model\ProductCategory: featured: true ``` -[notice] -A couple things to note here: - -- By assigning a value of `true` to the field, we defer to the model to infer the type for the field. To override that, we can always add a `type` property: - - ```yml - App\Model\Product: - fields: - onSale: - type: Boolean - ``` - -- The mapping of our field names to the `DataObject` property is case-insensitive. It is a -convention in GraphQL APIs to use lowerCamelCase fields, so this is given by default. - -[/notice] +> [!WARNING] +> A couple things to note here: +> +> - By assigning a value of `true` to the field, we defer to the model to infer the type for the field. To override that, we can always add a `type` property: +> +> ```yml +> App\Model\Product: +> fields: +> onSale: +> type: Boolean +> ``` +> +> - The mapping of our field names to the `DataObject` property is case-insensitive. It is a +> convention in GraphQL APIs to use lowerCamelCase fields, so this is given by default. ### Bulk loading models @@ -299,17 +292,15 @@ By default, four loaders are provided to you to help gather specific classnames: - `include: [ 'src/Model/*.model.php' ]` - `include: [ 'somevendor/somemodule: src/Model/*.php' ]` +> [!NOTE] +> `exclude` directives will always supersede `include` directives. + Each block starts with a collection of all classes that gets filtered as each loader runs. The primary job of a loader is to *remove* classes from the entire collection, not add them in. -[info] -`exclude` directives will always supersede `include` directives. -[/info] - -[info] -If you find that this paints with too big a brush, you can always override individual models explicitly in `models.yml`. -The bulk loaders run *before* the `models.yml` config is loaded. -[/info] +> [!NOTE] +> If you find that this paints with too big a brush, you can always override individual models explicitly in `models.yml`. +> The bulk loaders run *before* the `models.yml` config is loaded. #### `DataObject` subclasses are the default starting point @@ -454,10 +445,9 @@ modelConfig: type_formatter: ['App\GraphQL\Formatter', 'formatType'] ``` -[info] -In the above example, `DataObject` is the result of [`DataObjectModel::getIdentifier()`](api:SilverStripe\GraphQL\Schema\DataObject::getIdentifier()). -Each model class must declare one of these. -[/info] +> [!NOTE] +> In the above example, `DataObject` is the result of [`DataObjectModel::getIdentifier()`](api:SilverStripe\GraphQL\Schema\DataObject::getIdentifier()). +> Each model class must declare one of these. The formatting function in your `App\GraphQL\Formatter` class could look something like: diff --git a/en/02_Developer_Guides/19_GraphQL/02_working_with_dataobjects/02_query_plugins.md b/en/02_Developer_Guides/19_GraphQL/02_working_with_dataobjects/02_query_plugins.md index 4c8f538da..128f14c02 100644 --- a/en/02_Developer_Guides/19_GraphQL/02_working_with_dataobjects/02_query_plugins.md +++ b/en/02_Developer_Guides/19_GraphQL/02_working_with_dataobjects/02_query_plugins.md @@ -7,11 +7,10 @@ summary: Learn about some of the useful goodies that come pre-packaged with Data [CHILDREN asList] -[info] -You are viewing docs for silverstripe/graphql 4.x. -If you are using 3.x, documentation can be found -[in the GitHub repository](https://github.com/silverstripe/silverstripe-graphql/tree/3) -[/info] +> [!NOTE] +> You are viewing docs for silverstripe/graphql 4.x. +> If you are using 3.x, documentation can be found +> [in the GitHub repository](https://github.com/silverstripe/silverstripe-graphql/tree/3) ## `DataObject` query plugins @@ -62,13 +61,12 @@ query { } ``` -[notice] -If you're not familiar with the jargon of `edges` and `node`, don't worry too much about it -for now. It's just a pretty well-established convention for pagination in GraphQL, mostly owing -to its frequent use with [cursor-based pagination](https://graphql.org/learn/pagination/), which -isn't something we do in Silverstripe CMS. You can ignore `edges.node` and just use `nodes` if -you want to. -[/notice] +> [!WARNING] +> If you're not familiar with the jargon of `edges` and `node`, don't worry too much about it +> for now. It's just a pretty well-established convention for pagination in GraphQL, mostly owing +> to its frequent use with [cursor-based pagination](https://graphql.org/learn/pagination/), which +> isn't something we do in Silverstripe CMS. You can ignore `edges.node` and just use `nodes` if +> you want to. #### Disabling pagination @@ -145,10 +143,9 @@ query { } ``` -[notice] -While it is possible to filter using multiple comparators, segmenting them into -disjunctive groups (e.g. "OR" and "AND" clauses) is not yet supported. -[/notice] +> [!WARNING] +> While it is possible to filter using multiple comparators, segmenting them into +> disjunctive groups (e.g. "OR" and "AND" clauses) is not yet supported. Nested fields are supported by default: @@ -194,9 +191,8 @@ App\Model\ProductCategory: title: true ``` -[info] -You can also add all fields with `'*': true`, just like with standard model definitions. -[/info] +> [!NOTE] +> You can also add all fields with `'*': true`, just like with standard model definitions. ##### Adding non-native filter fields @@ -266,10 +262,9 @@ class ProductResolver } ``` -[info] -Custom filter fields are also a good opportunity to implement something like `filterByCallback` on your list for -particularly complex computations that cannot be done at the database level. -[/info] +> [!NOTE] +> Custom filter fields are also a good opportunity to implement something like `filterByCallback` on your list for +> particularly complex computations that cannot be done at the database level. #### Disabling the filter plugin diff --git a/en/02_Developer_Guides/19_GraphQL/02_working_with_dataobjects/03_permissions.md b/en/02_Developer_Guides/19_GraphQL/02_working_with_dataobjects/03_permissions.md index 3ab2d79f5..06f00b815 100644 --- a/en/02_Developer_Guides/19_GraphQL/02_working_with_dataobjects/03_permissions.md +++ b/en/02_Developer_Guides/19_GraphQL/02_working_with_dataobjects/03_permissions.md @@ -7,11 +7,10 @@ summary: A look at how permissions work for DataObject queries and mutations [CHILDREN asList] -[info] -You are viewing docs for silverstripe/graphql 4.x. -If you are using 3.x, documentation can be found -[in the GitHub repository](https://github.com/silverstripe/silverstripe-graphql/tree/3) -[/info] +> [!NOTE] +> You are viewing docs for silverstripe/graphql 4.x. +> If you are using 3.x, documentation can be found +> [in the GitHub repository](https://github.com/silverstripe/silverstripe-graphql/tree/3) ## `DataObject` operation permissions @@ -21,9 +20,8 @@ Please see [Model-Level Permissions](/developer_guides/model/permissions/#model- ### Mutation permssions -[info] -When mutations fail due to permission checks, they throw a [`PermissionsException`](api:SilverStripe\GraphQL\Schema\Exception\PermissionsException). -[/info] +> [!NOTE] +> When mutations fail due to permission checks, they throw a [`PermissionsException`](api:SilverStripe\GraphQL\Schema\Exception\PermissionsException). For `create`, if a singleton instance of the record being created doesn't pass a `canCreate($member)` check, the mutation will throw. @@ -38,19 +36,17 @@ For `delete`, if any of the given IDs don't pass a `canDelete($member)` check, t Query permissions are a bit more complicated, because they can either be in list form, (paginated or not), or a single item. Rather than throw, these permission checks work as filters. -[notice] -It is critical that you have a `canView()` method defined on your DataObjects. Without this, only admins are -assumed to have permission to view a record. -[/notice] +> [!WARNING] +> It is critical that you have a `canView()` method defined on your DataObjects. Without this, only admins are +> assumed to have permission to view a record. For `read` and `readOne` a plugin called `canView` will filter the result set by the `canView($member)` check. -[notice] -When paginated items fail a `canView()` check, the `pageInfo` field is not affected. -Limits and pages are determined through database queries. It would be too inefficient to perform in-memory checks on large data sets. -This can result in pages showing a smaller number of items than what the page should contain, but keeps the pagination calls consistent -for `limit` and `offset` parameters. -[/notice] +> [!WARNING] +> When paginated items fail a `canView()` check, the `pageInfo` field is not affected. +> Limits and pages are determined through database queries. It would be too inefficient to perform in-memory checks on large data sets. +> This can result in pages showing a smaller number of items than what the page should contain, but keeps the pagination calls consistent +> for `limit` and `offset` parameters. ### Disabling query permissions diff --git a/en/02_Developer_Guides/19_GraphQL/02_working_with_dataobjects/04_inheritance.md b/en/02_Developer_Guides/19_GraphQL/02_working_with_dataobjects/04_inheritance.md index 9207ded9d..f53b2ea6b 100644 --- a/en/02_Developer_Guides/19_GraphQL/02_working_with_dataobjects/04_inheritance.md +++ b/en/02_Developer_Guides/19_GraphQL/02_working_with_dataobjects/04_inheritance.md @@ -7,11 +7,10 @@ summary: Learn how inheritance is handled in DataObject model types [CHILDREN asList] -[info] -You are viewing docs for silverstripe/graphql 4.x. -If you are using 3.x, documentation can be found -[in the GitHub repository](https://github.com/silverstripe/silverstripe-graphql/tree/3) -[/info] +> [!NOTE] +> You are viewing docs for silverstripe/graphql 4.x. +> If you are using 3.x, documentation can be found +> [in the GitHub repository](https://github.com/silverstripe/silverstripe-graphql/tree/3) ## `DataObject` inheritance @@ -142,11 +141,10 @@ query { You can think of interfaces in this context as abstractions of *parent classes* - and the best part is they're generated automatically. We don't need to manually define or implement the interfaces. -[info] -A good way to determine whether you need an inline fragment is to ask -"can this field appear on any other types in the query?" If the answer is yes, you want to use an interface, -which is usually the parent class with the "Interface" suffix. -[/info] +> [!NOTE] +> A good way to determine whether you need an inline fragment is to ask +> "can this field appear on any other types in the query?" If the answer is yes, you want to use an interface, +> which is usually the parent class with the "Interface" suffix. ### Inheritance: a deep dive @@ -342,10 +340,9 @@ query { } ``` -[info] -The above example shows a query for elements on all elemental pages - but for most situations you will -probably only want to query the elements on one page at a time. -[/info] +> [!NOTE] +> The above example shows a query for elements on all elemental pages - but for most situations you will +> probably only want to query the elements on one page at a time. ### Optional: use unions instead of interfaces diff --git a/en/02_Developer_Guides/19_GraphQL/02_working_with_dataobjects/05_versioning.md b/en/02_Developer_Guides/19_GraphQL/02_working_with_dataobjects/05_versioning.md index b80baca8b..c68d4abb5 100644 --- a/en/02_Developer_Guides/19_GraphQL/02_working_with_dataobjects/05_versioning.md +++ b/en/02_Developer_Guides/19_GraphQL/02_working_with_dataobjects/05_versioning.md @@ -7,11 +7,10 @@ summary: A guide on how DataObject models with the Versioned extension behave in [CHILDREN asList] -[info] -You are viewing docs for silverstripe/graphql 4.x. -If you are using 3.x, documentation can be found -[in the GitHub repository](https://github.com/silverstripe/silverstripe-graphql/tree/3) -[/info] +> [!NOTE] +> You are viewing docs for silverstripe/graphql 4.x. +> If you are using 3.x, documentation can be found +> [in the GitHub repository](https://github.com/silverstripe/silverstripe-graphql/tree/3) ## Versioned content @@ -47,11 +46,10 @@ The `version` field on your `DataObject` will include the following fields: - `liveVersion`: Boolean (True if the version is the one that is currently live) - `latestDraftVersion`: Boolean (True if the version is the latest draft version) -[info] -Note that `author` and `publisher` are in relation to the given *version* of the object - these are -not necessarily the same as the author and publisher of the *original* record (i.e. the author may not -be the person who created the object, they're the person who saved a specific version of it). -[/info] +> [!NOTE] +> Note that `author` and `publisher` are in relation to the given *version* of the object - these are +> not necessarily the same as the author and publisher of the *original* record (i.e. the author may not +> be the person who created the object, they're the person who saved a specific version of it). Let's look at it in context: diff --git a/en/02_Developer_Guides/19_GraphQL/02_working_with_dataobjects/06_property_mapping.md b/en/02_Developer_Guides/19_GraphQL/02_working_with_dataobjects/06_property_mapping.md index ac21fc10f..1d3093446 100644 --- a/en/02_Developer_Guides/19_GraphQL/02_working_with_dataobjects/06_property_mapping.md +++ b/en/02_Developer_Guides/19_GraphQL/02_working_with_dataobjects/06_property_mapping.md @@ -7,11 +7,10 @@ summary: Learn how to customise field names, use dot syntax, and use aggregate f [CHILDREN asList] -[info] -You are viewing docs for silverstripe/graphql 4.x. -If you are using 3.x, documentation can be found -[in the GitHub repository](https://github.com/silverstripe/silverstripe-graphql/tree/3) -[/info] +> [!NOTE] +> You are viewing docs for silverstripe/graphql 4.x. +> If you are using 3.x, documentation can be found +> [in the GitHub repository](https://github.com/silverstripe/silverstripe-graphql/tree/3) ## Property mapping and dot syntax @@ -30,10 +29,9 @@ Page: property: Content ``` -[notice] -When using explicit property mapping, you must also define an explicit type, as it can -no longer be inferred. -[/notice] +> [!WARNING] +> When using explicit property mapping, you must also define an explicit type, as it can +> no longer be inferred. ### Dot-separated accessors diff --git a/en/02_Developer_Guides/19_GraphQL/02_working_with_dataobjects/07_nested_definitions.md b/en/02_Developer_Guides/19_GraphQL/02_working_with_dataobjects/07_nested_definitions.md index ea8d57fe0..3ffa82c86 100644 --- a/en/02_Developer_Guides/19_GraphQL/02_working_with_dataobjects/07_nested_definitions.md +++ b/en/02_Developer_Guides/19_GraphQL/02_working_with_dataobjects/07_nested_definitions.md @@ -6,11 +6,10 @@ summary: Define dependent types inline with a parent type [CHILDREN asList] -[info] -You are viewing docs for silverstripe/graphql 4.x. -If you are using 3.x, documentation can be found -[in the GitHub repository](https://github.com/silverstripe/silverstripe-graphql/tree/3) -[/info] +> [!NOTE] +> You are viewing docs for silverstripe/graphql 4.x. +> If you are using 3.x, documentation can be found +> [in the GitHub repository](https://github.com/silverstripe/silverstripe-graphql/tree/3) ## Nested type definitions @@ -50,9 +49,8 @@ App\Model\BlogCategory: fields: '*' ``` -[info] -You cannot define operations on nested types. They only accept fields. -[/info] +> [!NOTE] +> You cannot define operations on nested types. They only accept fields. ### Further reading diff --git a/en/02_Developer_Guides/19_GraphQL/02_working_with_dataobjects/index.md b/en/02_Developer_Guides/19_GraphQL/02_working_with_dataobjects/index.md index 87dea5144..c678d5012 100644 --- a/en/02_Developer_Guides/19_GraphQL/02_working_with_dataobjects/index.md +++ b/en/02_Developer_Guides/19_GraphQL/02_working_with_dataobjects/index.md @@ -11,10 +11,9 @@ and adding read/write operations. We'll also look at some of the plugins that ar like [sorting, filtering, and pagination](query_plugins), as well as some more advanced concepts like [permissions](permissions), [inheritance](inheritance) and [property mapping](property_mapping). -[info] -You are viewing docs for silverstripe/graphql 4.x. -If you are using 3.x, documentation can be found -[in the GitHub repository](https://github.com/silverstripe/silverstripe-graphql/tree/3) -[/info] +> [!NOTE] +> You are viewing docs for silverstripe/graphql 4.x. +> If you are using 3.x, documentation can be found +> [in the GitHub repository](https://github.com/silverstripe/silverstripe-graphql/tree/3) [CHILDREN] diff --git a/en/02_Developer_Guides/19_GraphQL/03_working_with_generic_types/01_creating_a_generic_type.md b/en/02_Developer_Guides/19_GraphQL/03_working_with_generic_types/01_creating_a_generic_type.md index 7a304f4fc..47094c2b6 100644 --- a/en/02_Developer_Guides/19_GraphQL/03_working_with_generic_types/01_creating_a_generic_type.md +++ b/en/02_Developer_Guides/19_GraphQL/03_working_with_generic_types/01_creating_a_generic_type.md @@ -7,11 +7,10 @@ summary: Creating a type that doesn't map to a DataObject [CHILDREN asList] -[info] -You are viewing docs for silverstripe/graphql 4.x. -If you are using 3.x, documentation can be found -[in the GitHub repository](https://github.com/silverstripe/silverstripe-graphql/tree/3) -[/info] +> [!NOTE] +> You are viewing docs for silverstripe/graphql 4.x. +> If you are using 3.x, documentation can be found +> [in the GitHub repository](https://github.com/silverstripe/silverstripe-graphql/tree/3) ## Creating a generic type diff --git a/en/02_Developer_Guides/19_GraphQL/03_working_with_generic_types/02_building_a_custom_query.md b/en/02_Developer_Guides/19_GraphQL/03_working_with_generic_types/02_building_a_custom_query.md index 8bcb99165..24a5b4891 100644 --- a/en/02_Developer_Guides/19_GraphQL/03_working_with_generic_types/02_building_a_custom_query.md +++ b/en/02_Developer_Guides/19_GraphQL/03_working_with_generic_types/02_building_a_custom_query.md @@ -6,11 +6,10 @@ summary: Add a custom query for any type of data [CHILDREN asList] -[info] -You are viewing docs for silverstripe/graphql 4.x. -If you are using 3.x, documentation can be found -[in the GitHub repository](https://github.com/silverstripe/silverstripe-graphql/tree/3) -[/info] +> [!NOTE] +> You are viewing docs for silverstripe/graphql 4.x. +> If you are using 3.x, documentation can be found +> [in the GitHub repository](https://github.com/silverstripe/silverstripe-graphql/tree/3) ## Building a custom query @@ -65,12 +64,11 @@ queries: resolver: [ 'App\GraphQL\Resolver\MyResolver', 'resolveCountries' ] ``` -[notice] -Note the difference in syntax here between the `type` and the `resolver` - the type declaration -*must* have quotes around it, because we are saying "this is a list of `Country` objects". The value -of this must be a YAML *string*. But the resolver must *not* be surrounded in quotes. It is explicitly -a YAML array, so that PHP recognises it as a `callable`. -[/notice] +> [!WARNING] +> Note the difference in syntax here between the `type` and the `resolver` - the type declaration +> *must* have quotes around it, because we are saying "this is a list of `Country` objects". The value +> of this must be a YAML *string*. But the resolver must *not* be surrounded in quotes. It is explicitly +> a YAML array, so that PHP recognises it as a `callable`. Now, we just have to build the schema: @@ -114,13 +112,12 @@ And the expected response: } ``` -[notice] -Keep in mind that [plugins](../working_with_DataObjects/query_plugins) -don't apply in this context - at least without updating the resolver -to account for them. Most importantly this means you need to -implement your own `canView()` checks. It also means you need -to add your own filter functionality, such as [pagination](adding_pagination). -[/notice] +> [!WARNING] +> Keep in mind that [plugins](../working_with_DataObjects/query_plugins) +> don't apply in this context - at least without updating the resolver +> to account for them. Most importantly this means you need to +> implement your own `canView()` checks. It also means you need +> to add your own filter functionality, such as [pagination](adding_pagination). ## Resolver method arguments diff --git a/en/02_Developer_Guides/19_GraphQL/03_working_with_generic_types/03_resolver_discovery.md b/en/02_Developer_Guides/19_GraphQL/03_working_with_generic_types/03_resolver_discovery.md index f28c073f9..a6180505a 100644 --- a/en/02_Developer_Guides/19_GraphQL/03_working_with_generic_types/03_resolver_discovery.md +++ b/en/02_Developer_Guides/19_GraphQL/03_working_with_generic_types/03_resolver_discovery.md @@ -7,11 +7,10 @@ summary: How you can opt out of mapping fields to resolvers by adhering to namin [CHILDREN asList] -[info] -You are viewing docs for silverstripe/graphql 4.x. -If you are using 3.x, documentation can be found -[in the GitHub repository](https://github.com/silverstripe/silverstripe-graphql/tree/3) -[/info] +> [!NOTE] +> You are viewing docs for silverstripe/graphql 4.x. +> If you are using 3.x, documentation can be found +> [in the GitHub repository](https://github.com/silverstripe/silverstripe-graphql/tree/3) ## The resolver discovery pattern diff --git a/en/02_Developer_Guides/19_GraphQL/03_working_with_generic_types/04_adding_arguments.md b/en/02_Developer_Guides/19_GraphQL/03_working_with_generic_types/04_adding_arguments.md index 3645c4c02..aa7d65d6c 100644 --- a/en/02_Developer_Guides/19_GraphQL/03_working_with_generic_types/04_adding_arguments.md +++ b/en/02_Developer_Guides/19_GraphQL/03_working_with_generic_types/04_adding_arguments.md @@ -7,11 +7,10 @@ summary: Add arguments to your fields, queries, and mutations [CHILDREN asList] -[info] -You are viewing docs for silverstripe/graphql 4.x. -If you are using 3.x, documentation can be found -[in the GitHub repository](https://github.com/silverstripe/silverstripe-graphql/tree/3) -[/info] +> [!NOTE] +> You are viewing docs for silverstripe/graphql 4.x. +> If you are using 3.x, documentation can be found +> [in the GitHub repository](https://github.com/silverstripe/silverstripe-graphql/tree/3) ## Adding arguments @@ -24,11 +23,10 @@ queries: 'readCountries(limit: Int!)': '[Country]' ``` -[hint] -In the above example, the `limit` argument is *required* by making it non-nullable. If you want to be able -to get an un-filtered list, you can instead allow the argument to be nullable by removing the `!`: -`'readCountries(limit: Int)': '[Country]'` -[/hint] +> [!TIP] +> In the above example, the `limit` argument is *required* by making it non-nullable. If you want to be able +> to get an un-filtered list, you can instead allow the argument to be nullable by removing the `!`: +> `'readCountries(limit: Int)': '[Country]'` We've provided the required argument `limit` to the query, which will allow us to truncate the results. Let's update the resolver accordingly. diff --git a/en/02_Developer_Guides/19_GraphQL/03_working_with_generic_types/05_adding_pagination.md b/en/02_Developer_Guides/19_GraphQL/03_working_with_generic_types/05_adding_pagination.md index dfd770a86..6b6a801ef 100644 --- a/en/02_Developer_Guides/19_GraphQL/03_working_with_generic_types/05_adding_pagination.md +++ b/en/02_Developer_Guides/19_GraphQL/03_working_with_generic_types/05_adding_pagination.md @@ -6,11 +6,10 @@ summary: Add the pagination plugin to a generic query [CHILDREN asList] -[info] -You are viewing docs for silverstripe/graphql 4.x. -If you are using 3.x, documentation can be found -[in the GitHub repository](https://github.com/silverstripe/silverstripe-graphql/tree/3) -[/info] +> [!NOTE] +> You are viewing docs for silverstripe/graphql 4.x. +> If you are using 3.x, documentation can be found +> [in the GitHub repository](https://github.com/silverstripe/silverstripe-graphql/tree/3) ## Adding pagination @@ -33,12 +32,11 @@ Let's take this a step further and paginate it using a plugin. Since pagination is a fairly common task, we can take advantage of some reusable code here and just add a generic plugin for paginating. -[notice] -If you're paginating a `DataList`, you might want to consider using models with read operations (instead of declaring -them as generic types with generic queries), which paginate by default using the `paginateList` plugin. -You can use generic typing and follow the below instructions too but it requires code that, for `DataObject` models, -you get for free. -[/notice] +> [!WARNING] +> If you're paginating a `DataList`, you might want to consider using models with read operations (instead of declaring +> them as generic types with generic queries), which paginate by default using the `paginateList` plugin. +> You can use generic typing and follow the below instructions too but it requires code that, for `DataObject` models, +> you get for free. Let's add the plugin to our query: diff --git a/en/02_Developer_Guides/19_GraphQL/03_working_with_generic_types/06_adding_descriptions.md b/en/02_Developer_Guides/19_GraphQL/03_working_with_generic_types/06_adding_descriptions.md index 7a47a4544..7f873b1f8 100644 --- a/en/02_Developer_Guides/19_GraphQL/03_working_with_generic_types/06_adding_descriptions.md +++ b/en/02_Developer_Guides/19_GraphQL/03_working_with_generic_types/06_adding_descriptions.md @@ -6,11 +6,10 @@ summary: Add descriptions to just about anything in your schema to improve your [CHILDREN asList] -[info] -You are viewing docs for silverstripe/graphql 4.x. -If you are using 3.x, documentation can be found -[in the GitHub repository](https://github.com/silverstripe/silverstripe-graphql/tree/3) -[/info] +> [!NOTE] +> You are viewing docs for silverstripe/graphql 4.x. +> If you are using 3.x, documentation can be found +> [in the GitHub repository](https://github.com/silverstripe/silverstripe-graphql/tree/3) ## Adding descriptions diff --git a/en/02_Developer_Guides/19_GraphQL/03_working_with_generic_types/07_enums_unions_and_interfaces.md b/en/02_Developer_Guides/19_GraphQL/03_working_with_generic_types/07_enums_unions_and_interfaces.md index 2877f585b..186f91546 100644 --- a/en/02_Developer_Guides/19_GraphQL/03_working_with_generic_types/07_enums_unions_and_interfaces.md +++ b/en/02_Developer_Guides/19_GraphQL/03_working_with_generic_types/07_enums_unions_and_interfaces.md @@ -6,11 +6,10 @@ summary: Add some non-object types to your schema [CHILDREN asList] -[info] -You are viewing docs for silverstripe/graphql 4.x. -If you are using 3.x, documentation can be found -[in the GitHub repository](https://github.com/silverstripe/silverstripe-graphql/tree/3) -[/info] +> [!NOTE] +> You are viewing docs for silverstripe/graphql 4.x. +> If you are using 3.x, documentation can be found +> [in the GitHub repository](https://github.com/silverstripe/silverstripe-graphql/tree/3) ## Enums, unions, and interfaces diff --git a/en/02_Developer_Guides/19_GraphQL/03_working_with_generic_types/index.md b/en/02_Developer_Guides/19_GraphQL/03_working_with_generic_types/index.md index 7b8e008a2..9ac34484e 100644 --- a/en/02_Developer_Guides/19_GraphQL/03_working_with_generic_types/index.md +++ b/en/02_Developer_Guides/19_GraphQL/03_working_with_generic_types/index.md @@ -6,6 +6,11 @@ icon: clipboard # Working with generic types +> [!NOTE] +> You are viewing docs for silverstripe/graphql 4.x. +> If you are using 3.x, documentation can be found +> [in the GitHub repository](https://github.com/silverstripe/silverstripe-graphql/tree/3) + In this section of the documentation, we cover the fundamentals that are behind a lot of the magic that goes into making `DataObject` types work. We'll create some types that are not based on DataObjects at all, and we'll write some custom queries from the ground up. @@ -13,16 +18,9 @@ write some custom queries from the ground up. This is useful for situations where your data doesn't come from a `DataObject`, or where you have very specific requirements for your GraphQL API that don't easily map to the schema of your `DataObject` classes. -[info] -Just because we won't be using DataObjects in this example doesn't mean you can't do it - you can absolutely -declare `DataObject` classes as generic types. You would lose a lot of the benefits of the `DataObject` model -in doing so, but this lower level API may suit your needs for very specific use cases. -[/info] - -[info] -You are viewing docs for silverstripe/graphql 4.x. -If you are using 3.x, documentation can be found -[in the GitHub repository](https://github.com/silverstripe/silverstripe-graphql/tree/3) -[/info] +> [!NOTE] +> Just because we won't be using DataObjects in this example doesn't mean you can't do it - you can absolutely +> declare `DataObject` classes as generic types. You would lose a lot of the benefits of the `DataObject` model +> in doing so, but this lower level API may suit your needs for very specific use cases. [CHILDREN] diff --git a/en/02_Developer_Guides/19_GraphQL/04_security_and_best_practices/01_authentication.md b/en/02_Developer_Guides/19_GraphQL/04_security_and_best_practices/01_authentication.md index 44ab4e4b7..7b50e4ed8 100644 --- a/en/02_Developer_Guides/19_GraphQL/04_security_and_best_practices/01_authentication.md +++ b/en/02_Developer_Guides/19_GraphQL/04_security_and_best_practices/01_authentication.md @@ -8,11 +8,10 @@ icon: user-lock [CHILDREN asList] -[info] -You are viewing docs for silverstripe/graphql 4.x. -If you are using 3.x, documentation can be found -[in the GitHub repository](https://github.com/silverstripe/silverstripe-graphql/tree/3) -[/info] +> [!NOTE] +> You are viewing docs for silverstripe/graphql 4.x. +> If you are using 3.x, documentation can be found +> [in the GitHub repository](https://github.com/silverstripe/silverstripe-graphql/tree/3) ## Authentication @@ -24,11 +23,10 @@ the same `Member` session is used to authenticate GraphQL requests, however if y are performing requests from an anonymous/external application you may need to authenticate before you can complete a request. -[notice] -Please note that when implementing GraphQL resources it is the developer's -responsibility to ensure that permission checks are implemented wherever -resources are accessed. -[/notice] +> [!WARNING] +> Please note that when implementing GraphQL resources it is the developer's +> responsibility to ensure that permission checks are implemented wherever +> resources are accessed. ### Default authentication @@ -99,9 +97,8 @@ is applicable in the current request context (provided as an argument). Here's an example for implementing HTTP basic authentication: -[notice] -Note that basic authentication for GraphQL will bypass Multi-Factor Authentication (MFA) if that's enabled. Using basic authentication for GraphQL is considered insecure if you are using MFA. -[/notice] +> [!WARNING] +> Note that basic authentication for GraphQL will bypass Multi-Factor Authentication (MFA) if that's enabled. Using basic authentication for GraphQL is considered insecure if you are using MFA. ```yml SilverStripe\GraphQL\Auth\Handler: diff --git a/en/02_Developer_Guides/19_GraphQL/04_security_and_best_practices/02_cors.md b/en/02_Developer_Guides/19_GraphQL/04_security_and_best_practices/02_cors.md index 3c8d612e4..6c6c3ec6a 100644 --- a/en/02_Developer_Guides/19_GraphQL/04_security_and_best_practices/02_cors.md +++ b/en/02_Developer_Guides/19_GraphQL/04_security_and_best_practices/02_cors.md @@ -7,11 +7,10 @@ summary: Ensure that requests to your API come from a whitelist of origins [CHILDREN asList] -[info] -You are viewing docs for silverstripe/graphql 4.x. -If you are using 3.x, documentation can be found -[in the GitHub repository](https://github.com/silverstripe/silverstripe-graphql/tree/3) -[/info] +> [!NOTE] +> You are viewing docs for silverstripe/graphql 4.x. +> If you are using 3.x, documentation can be found +> [in the GitHub repository](https://github.com/silverstripe/silverstripe-graphql/tree/3) ## Cross-Origin resource sharing (CORS) @@ -67,10 +66,9 @@ Once you have enabled CORS you can then control four new headers in the HTTP Res Allow-Headers: 'Authorization, Content-Type, Content-Language' ``` - [notice] - If you add extra headers to your GraphQL server, you will need to write a - custom resolver function to handle the response. - [/notice] + > [!WARNING] + > If you add extra headers to your GraphQL server, you will need to write a + > custom resolver function to handle the response. 1. **Access-Control-Allow-Methods.** diff --git a/en/02_Developer_Guides/19_GraphQL/04_security_and_best_practices/03_csrf_protection.md b/en/02_Developer_Guides/19_GraphQL/04_security_and_best_practices/03_csrf_protection.md index 9a990a742..de1dd25b4 100644 --- a/en/02_Developer_Guides/19_GraphQL/04_security_and_best_practices/03_csrf_protection.md +++ b/en/02_Developer_Guides/19_GraphQL/04_security_and_best_practices/03_csrf_protection.md @@ -6,11 +6,10 @@ summary: Protect destructive actions from cross-site request forgery [CHILDREN asList] -[info] -You are viewing docs for silverstripe/graphql 4.x. -If you are using 3.x, documentation can be found -[in the GitHub repository](https://github.com/silverstripe/silverstripe-graphql/tree/3) -[/info] +> [!NOTE] +> You are viewing docs for silverstripe/graphql 4.x. +> If you are using 3.x, documentation can be found +> [in the GitHub repository](https://github.com/silverstripe/silverstripe-graphql/tree/3) ## CSRF tokens (required for mutations) diff --git a/en/02_Developer_Guides/19_GraphQL/04_security_and_best_practices/04_http_method_checking.md b/en/02_Developer_Guides/19_GraphQL/04_security_and_best_practices/04_http_method_checking.md index 403aa4241..a7bf9172c 100644 --- a/en/02_Developer_Guides/19_GraphQL/04_security_and_best_practices/04_http_method_checking.md +++ b/en/02_Developer_Guides/19_GraphQL/04_security_and_best_practices/04_http_method_checking.md @@ -7,11 +7,10 @@ summary: Ensure requests are GET or POST [CHILDREN asList] -[info] -You are viewing docs for silverstripe/graphql 4.x. -If you are using 3.x, documentation can be found -[in the GitHub repository](https://github.com/silverstripe/silverstripe-graphql/tree/3) -[/info] +> [!NOTE] +> You are viewing docs for silverstripe/graphql 4.x. +> If you are using 3.x, documentation can be found +> [in the GitHub repository](https://github.com/silverstripe/silverstripe-graphql/tree/3) ## Strict HTTP method checking diff --git a/en/02_Developer_Guides/19_GraphQL/04_security_and_best_practices/05_recursive_or_complex_queries.md b/en/02_Developer_Guides/19_GraphQL/04_security_and_best_practices/05_recursive_or_complex_queries.md index ea03dd461..63cfb3f9d 100644 --- a/en/02_Developer_Guides/19_GraphQL/04_security_and_best_practices/05_recursive_or_complex_queries.md +++ b/en/02_Developer_Guides/19_GraphQL/04_security_and_best_practices/05_recursive_or_complex_queries.md @@ -30,9 +30,8 @@ SilverStripe\GraphQL\Schema\Schema: max_query_complexity: 100 # default unlimited ``` -[info] -For calculating the query complexity, every field in the query gets a default score 1 (including ObjectType nodes). Total complexity of the query is the sum of all field scores. -[/info] +> [!NOTE] +> For calculating the query complexity, every field in the query gets a default score 1 (including ObjectType nodes). Total complexity of the query is the sum of all field scores. You can also configure these settings for individual schemas. This allows you to fine-tune the security of your custom public-facing schema without affecting the security of the schema used in the CMS. To do so, either replace `'*'` with the name of your schema in the YAML configuration above, or set the values under the `config` key for your schema using preferred file structure as defined in [configuring your schema](../getting_started/configuring_your_schema/). For example: diff --git a/en/02_Developer_Guides/19_GraphQL/04_security_and_best_practices/index.md b/en/02_Developer_Guides/19_GraphQL/04_security_and_best_practices/index.md index 7f6b4b512..e955fd049 100644 --- a/en/02_Developer_Guides/19_GraphQL/04_security_and_best_practices/index.md +++ b/en/02_Developer_Guides/19_GraphQL/04_security_and_best_practices/index.md @@ -9,10 +9,9 @@ icon: user-lock In this section we'll cover several options you have for keeping your GraphQL API secure and compliant with best practices. Some of these tools require configuration, while others come pre-installed. -[info] -You are viewing docs for silverstripe/graphql 4.x. -If you are using 3.x, documentation can be found -[in the GitHub repository](https://github.com/silverstripe/silverstripe-graphql/tree/3) -[/info] +> [!NOTE] +> You are viewing docs for silverstripe/graphql 4.x. +> If you are using 3.x, documentation can be found +> [in the GitHub repository](https://github.com/silverstripe/silverstripe-graphql/tree/3) [CHILDREN] diff --git a/en/02_Developer_Guides/19_GraphQL/05_plugins/01_overview.md b/en/02_Developer_Guides/19_GraphQL/05_plugins/01_overview.md index daec4045e..00faa825c 100644 --- a/en/02_Developer_Guides/19_GraphQL/05_plugins/01_overview.md +++ b/en/02_Developer_Guides/19_GraphQL/05_plugins/01_overview.md @@ -7,11 +7,10 @@ summary: An overview of how plugins work with the GraphQL schema [CHILDREN asList] -[info] -You are viewing docs for silverstripe/graphql 4.x. -If you are using 3.x, documentation can be found -[in the GitHub repository](https://github.com/silverstripe/silverstripe-graphql/tree/3) -[/info] +> [!NOTE] +> You are viewing docs for silverstripe/graphql 4.x. +> If you are using 3.x, documentation can be found +> [in the GitHub repository](https://github.com/silverstripe/silverstripe-graphql/tree/3) ## What are plugins? diff --git a/en/02_Developer_Guides/19_GraphQL/05_plugins/02_writing_a_simple_plugin.md b/en/02_Developer_Guides/19_GraphQL/05_plugins/02_writing_a_simple_plugin.md index 92199c316..6d3956b0d 100644 --- a/en/02_Developer_Guides/19_GraphQL/05_plugins/02_writing_a_simple_plugin.md +++ b/en/02_Developer_Guides/19_GraphQL/05_plugins/02_writing_a_simple_plugin.md @@ -7,11 +7,10 @@ summary: In this tutorial, we add a simple plugin for string fields [CHILDREN asList] -[info] -You are viewing docs for silverstripe/graphql 4.x. -If you are using 3.x, documentation can be found -[in the GitHub repository](https://github.com/silverstripe/silverstripe-graphql/tree/3) -[/info] +> [!NOTE] +> You are viewing docs for silverstripe/graphql 4.x. +> If you are using 3.x, documentation can be found +> [in the GitHub repository](https://github.com/silverstripe/silverstripe-graphql/tree/3) ## Writing a simple plugin diff --git a/en/02_Developer_Guides/19_GraphQL/05_plugins/03_writing_a_complex_plugin.md b/en/02_Developer_Guides/19_GraphQL/05_plugins/03_writing_a_complex_plugin.md index d060590dc..97bb69084 100644 --- a/en/02_Developer_Guides/19_GraphQL/05_plugins/03_writing_a_complex_plugin.md +++ b/en/02_Developer_Guides/19_GraphQL/05_plugins/03_writing_a_complex_plugin.md @@ -6,11 +6,10 @@ summary: In this tutorial, we'll create a plugin that affects models, queries, a [CHILDREN asList] -[info] -You are viewing docs for silverstripe/graphql 4.x. -If you are using 3.x, documentation can be found -[in the GitHub repository](https://github.com/silverstripe/silverstripe-graphql/tree/3) -[/info] +> [!NOTE] +> You are viewing docs for silverstripe/graphql 4.x. +> If you are using 3.x, documentation can be found +> [in the GitHub repository](https://github.com/silverstripe/silverstripe-graphql/tree/3) ## Writing a complex plugin @@ -282,11 +281,10 @@ we could filter the result set by a list of `IDs` early on, which would allow us a `DataList` throughout the whole cycle, but this would force us to loop over an unlimited result set, and that's never a good idea. -[notice] -If you've picked up on the inconsistency that the `pageInfo` property is now inaccurate, this is a long-standing -issue with doing post-query filters. Ideally, any middleware that filters a `DataList` should do it at the query level, -but that's not always possible. -[/notice] +> [!WARNING] +> If you've picked up on the inconsistency that the `pageInfo` property is now inaccurate, this is a long-standing +> issue with doing post-query filters. Ideally, any middleware that filters a `DataList` should do it at the query level, +> but that's not always possible. ### Step 5: apply the plugins diff --git a/en/02_Developer_Guides/19_GraphQL/05_plugins/index.md b/en/02_Developer_Guides/19_GraphQL/05_plugins/index.md index b40ff5aae..7fab20f95 100644 --- a/en/02_Developer_Guides/19_GraphQL/05_plugins/index.md +++ b/en/02_Developer_Guides/19_GraphQL/05_plugins/index.md @@ -10,10 +10,9 @@ Plugins play a critical role in distributing reusable functionality across your everything loaded into the schema, including types, fields, queries, mutations, and even specifically to model types and their fields and operations. -[info] -You are viewing docs for silverstripe/graphql 4.x. -If you are using 3.x, documentation can be found -[in the GitHub repository](https://github.com/silverstripe/silverstripe-graphql/tree/3) -[/info] +> [!NOTE] +> You are viewing docs for silverstripe/graphql 4.x. +> If you are using 3.x, documentation can be found +> [in the GitHub repository](https://github.com/silverstripe/silverstripe-graphql/tree/3) [CHILDREN] diff --git a/en/02_Developer_Guides/19_GraphQL/06_extending/adding_a_custom_model.md b/en/02_Developer_Guides/19_GraphQL/06_extending/adding_a_custom_model.md index e2f483841..ebd582ea6 100644 --- a/en/02_Developer_Guides/19_GraphQL/06_extending/adding_a_custom_model.md +++ b/en/02_Developer_Guides/19_GraphQL/06_extending/adding_a_custom_model.md @@ -6,11 +6,10 @@ summary: Add a new class-backed type beyond DataObject [CHILDREN asList] -[info] -You are viewing docs for silverstripe/graphql 4.x. -If you are using 3.x, documentation can be found -[in the GitHub repository](https://github.com/silverstripe/silverstripe-graphql/tree/3) -[/info] +> [!NOTE] +> You are viewing docs for silverstripe/graphql 4.x. +> If you are using 3.x, documentation can be found +> [in the GitHub repository](https://github.com/silverstripe/silverstripe-graphql/tree/3) ## Adding a custom model diff --git a/en/02_Developer_Guides/19_GraphQL/06_extending/adding_a_custom_operation.md b/en/02_Developer_Guides/19_GraphQL/06_extending/adding_a_custom_operation.md index 715506fc3..bcdcb80c3 100644 --- a/en/02_Developer_Guides/19_GraphQL/06_extending/adding_a_custom_operation.md +++ b/en/02_Developer_Guides/19_GraphQL/06_extending/adding_a_custom_operation.md @@ -6,11 +6,10 @@ summary: Add a new operation for model types [CHILDREN asList] -[info] -You are viewing docs for silverstripe/graphql 4.x. -If you are using 3.x, documentation can be found -[in the GitHub repository](https://github.com/silverstripe/silverstripe-graphql/tree/3) -[/info] +> [!NOTE] +> You are viewing docs for silverstripe/graphql 4.x. +> If you are using 3.x, documentation can be found +> [in the GitHub repository](https://github.com/silverstripe/silverstripe-graphql/tree/3) ## Adding a custom operation diff --git a/en/02_Developer_Guides/19_GraphQL/06_extending/adding_middleware.md b/en/02_Developer_Guides/19_GraphQL/06_extending/adding_middleware.md index 3a2194b29..402e1a054 100644 --- a/en/02_Developer_Guides/19_GraphQL/06_extending/adding_middleware.md +++ b/en/02_Developer_Guides/19_GraphQL/06_extending/adding_middleware.md @@ -6,11 +6,10 @@ summary: Add middleware to to extend query execution [CHILDREN asList] -[info] -You are viewing docs for silverstripe/graphql 4.x. -If you are using 3.x, documentation can be found -[in the GitHub repository](https://github.com/silverstripe/silverstripe-graphql/tree/3) -[/info] +> [!NOTE] +> You are viewing docs for silverstripe/graphql 4.x. +> If you are using 3.x, documentation can be found +> [in the GitHub repository](https://github.com/silverstripe/silverstripe-graphql/tree/3) ## Adding middleware @@ -23,10 +22,9 @@ In `silverstripe/graphql`, middleware is used for query execution, but could ostensibly be used elsewhere too if the API ever accomodates such an expansion. -[notice] -The middleware API in the `silverstripe/graphql` module is separate from other common middleware -APIs in Silverstripe CMS, such as `HTTPMiddleware`. The two are not interchangable. -[/notice] +> [!WARNING] +> The middleware API in the `silverstripe/graphql` module is separate from other common middleware +> APIs in Silverstripe CMS, such as `HTTPMiddleware`. The two are not interchangable. The signature for middleware (defined in [`QueryMiddleware`](api:SilverStripe\GraphQL\Middleware\QueryMiddleware)) looks like this: diff --git a/en/02_Developer_Guides/19_GraphQL/06_extending/global_schema.md b/en/02_Developer_Guides/19_GraphQL/06_extending/global_schema.md index a6893e90b..38a4d8cbb 100644 --- a/en/02_Developer_Guides/19_GraphQL/06_extending/global_schema.md +++ b/en/02_Developer_Guides/19_GraphQL/06_extending/global_schema.md @@ -7,11 +7,10 @@ summary: How to push modifications to every schema in the project [CHILDREN asList] -[info] -You are viewing docs for silverstripe/graphql 4.x. -If you are using 3.x, documentation can be found -[in the GitHub repository](https://github.com/silverstripe/silverstripe-graphql/tree/3) -[/info] +> [!NOTE] +> You are viewing docs for silverstripe/graphql 4.x. +> If you are using 3.x, documentation can be found +> [in the GitHub repository](https://github.com/silverstripe/silverstripe-graphql/tree/3) ## The global schema diff --git a/en/02_Developer_Guides/19_GraphQL/06_extending/index.md b/en/02_Developer_Guides/19_GraphQL/06_extending/index.md index a00561d32..dbfacc274 100644 --- a/en/02_Developer_Guides/19_GraphQL/06_extending/index.md +++ b/en/02_Developer_Guides/19_GraphQL/06_extending/index.md @@ -10,10 +10,9 @@ In this section of the documentation, we'll look at some advanced features for developers who want to extend their GraphQL server using custom models, middleware, and new operations. -[info] -You are viewing docs for silverstripe/graphql 4.x. -If you are using 3.x, documentation can be found -[in the GitHub repository](https://github.com/silverstripe/silverstripe-graphql/tree/3) -[/info] +> [!NOTE] +> You are viewing docs for silverstripe/graphql 4.x. +> If you are using 3.x, documentation can be found +> [in the GitHub repository](https://github.com/silverstripe/silverstripe-graphql/tree/3) [CHILDREN] diff --git a/en/02_Developer_Guides/19_GraphQL/07_tips_and_tricks.md b/en/02_Developer_Guides/19_GraphQL/07_tips_and_tricks.md index 1ed4da497..91944929f 100644 --- a/en/02_Developer_Guides/19_GraphQL/07_tips_and_tricks.md +++ b/en/02_Developer_Guides/19_GraphQL/07_tips_and_tricks.md @@ -5,11 +5,10 @@ summary: Miscellaneous useful tips for working with your GraphQL schema # Tips & tricks -[info] -You are viewing docs for silverstripe/graphql 4.x. -If you are using 3.x, documentation can be found -[in the GitHub repository](https://github.com/silverstripe/silverstripe-graphql/tree/3) -[/info] +> [!NOTE] +> You are viewing docs for silverstripe/graphql 4.x. +> If you are using 3.x, documentation can be found +> [in the GitHub repository](https://github.com/silverstripe/silverstripe-graphql/tree/3) ## Debugging the generated code @@ -21,11 +20,10 @@ of differentiating between the two. When debugging, however, it's much easier if these classnames are human-readable. To turn on debug mode, add `DEBUG_SCHEMA=1` to your environment file. The classnames and filenames in the generated code directory will then match their type names. -[warning] -Take care not to use `DEBUG_SCHEMA=1` as an inline environment variable to your build command, e.g. -`DEBUG_SCHEMA=1 vendor/bin/sake dev/graphql/build` because any activity that happens at run time, e.g. querying the schema -will fail, since the environment variable is no longer set. -[/warning] +> [!WARNING] +> Take care not to use `DEBUG_SCHEMA=1` as an inline environment variable to your build command, e.g. +> `DEBUG_SCHEMA=1 vendor/bin/sake dev/graphql/build` because any activity that happens at run time, e.g. querying the schema +> will fail, since the environment variable is no longer set. In live mode, full obfuscation kicks in and the filenames become unreadable. You can only determine the type they map to by looking at the generated classes and finding the `// @type:` inline comment, e.g. `// @type:Page`. @@ -72,9 +70,8 @@ By default three are provided, which cover most use cases: All of these implementations can be configured through `Injector`. -[notice] -Note that each schema gets its own set of persisted queries. In these examples, we're using the `default` schema. -[/notice] +> [!WARNING] +> Note that each schema gets its own set of persisted queries. In these examples, we're using the `default` schema. #### FileProvider @@ -93,9 +90,8 @@ A flat file in the path `/var/www/project/query-mapping.json` should contain som {"someUniqueID":"query{validateToken{Valid Message Code}}"} ``` -[notice] -The file path must be absolute. -[/notice] +> [!WARNING] +> The file path must be absolute. #### HTTPProvider @@ -133,9 +129,8 @@ To access a persisted query, simply pass an `id` parameter in the request in lie `GET http://example.com/graphql?id=someID` -[notice] -Note that if you pass `query` along with `id`, an exception will be thrown. -[/notice] +> [!WARNING] +> Note that if you pass `query` along with `id`, an exception will be thrown. ## Query caching (caution: EXPERIMENTAL) @@ -163,9 +158,8 @@ SilverStripe\ORM\DataObject: - SilverStripe\GraphQL\Extensions\QueryRecorderExtension ``` -[warning] -This feature is experimental, and has not been thoroughly evaluated for security. Use at your own risk. -[/warning] +> [!WARNING] +> This feature is experimental, and has not been thoroughly evaluated for security. Use at your own risk. ## Schema introspection {#schema-introspection} diff --git a/en/02_Developer_Guides/19_GraphQL/08_architecture_diagrams.md b/en/02_Developer_Guides/19_GraphQL/08_architecture_diagrams.md index 73731599e..76ec704c6 100644 --- a/en/02_Developer_Guides/19_GraphQL/08_architecture_diagrams.md +++ b/en/02_Developer_Guides/19_GraphQL/08_architecture_diagrams.md @@ -14,9 +14,8 @@ In GraphQL 3, the schema is built at request time, adding significant overhead t In GraphQL 4, the schema is generated during a build step, which generates code generation artefacts. These artefacts are executed at request time, meaning the schema itself imposes no penalty on the response time. -[info] -A useful analog to these two different approaches is a dynamic website versus a static website. In the case of the former, the PHP process is doing work on every single request. In the case of the latter, it does a lot of work once, in a separate context, in exchange for doing zero work on every page request. -[/info] +> [!NOTE] +> A useful analog to these two different approaches is a dynamic website versus a static website. In the case of the former, the PHP process is doing work on every single request. In the case of the latter, it does a lot of work once, in a separate context, in exchange for doing zero work on every page request. ## The build process @@ -42,9 +41,8 @@ There are two key processes that happen at request time. Although they're run in The controller receives the query as a request parameter and persists it as state. It then fetches the schema from the schema storage service (generated code). Then, the query is passed to a query handler service that runs the query through the generated schema code, into a stack of resolvers that execute in serial, much like a stack of middlewares, until finally the response is generated and sent down the wire. -[info] -The concept of the "resolver stack" is illustrated later in this document. -[/info] +> [!NOTE] +> The concept of the "resolver stack" is illustrated later in this document. ## Schema composition @@ -107,9 +105,8 @@ Sometimes, a resolver needs to be used in multiple contexts, for instance, a gen To solve this problem, we can use "resolver context". -[info] -The word "context" is a bit overloaded here. This section has nothing to do with the `$context` parameter that is passed to all resolvers. -[/info] +> [!NOTE] +> The word "context" is a bit overloaded here. This section has nothing to do with the `$context` parameter that is passed to all resolvers. When resolvers have context, they must be factories, or functions that return functions, using the following pattern: diff --git a/en/02_Developer_Guides/19_GraphQL/index.md b/en/02_Developer_Guides/19_GraphQL/index.md index d0b71eaac..2b9fa6e94 100644 --- a/en/02_Developer_Guides/19_GraphQL/index.md +++ b/en/02_Developer_Guides/19_GraphQL/index.md @@ -6,10 +6,9 @@ system. For more information on GraphQL in general, visit its [documentation site](https://graphql.org). -[info] -You are viewing docs for silverstripe/graphql 4.x. -If you are using 3.x, documentation can be found -[in the GitHub repository](https://github.com/silverstripe/silverstripe-graphql/tree/3) -[/info] +> [!NOTE] +> You are viewing docs for silverstripe/graphql 4.x. +> If you are using 3.x, documentation can be found +> [in the GitHub repository](https://github.com/silverstripe/silverstripe-graphql/tree/3) [CHILDREN includeFolders] diff --git a/en/03_Upgrading/04_Upgrading_project.md b/en/03_Upgrading/04_Upgrading_project.md index 40dca460a..6daf63646 100644 --- a/en/03_Upgrading/04_Upgrading_project.md +++ b/en/03_Upgrading/04_Upgrading_project.md @@ -77,9 +77,8 @@ Before you begin the upgrade process, make sure you meet these pre-requisites. - Backup your database content. - Backup your codebase (use version control if possible). -[warning] -Never update a website on the live server. Get it working on a development copy first! -[/warning] +> [!WARNING] +> Never update a website on the live server. Get it working on a development copy first! ### Install composer @@ -126,9 +125,8 @@ Each command in the upgrader has somewhat different arguments. However, most of - `--write` which tells the upgrader to apply changes to your code base - `--root-dir` which can be use to explicitly specify the root of your project. If this is not specified then the current working directory is assumed to be the root of the project. -[info] -Sample upgrader commands in this guide assume your working directory is the root of your Silverstripe CMS project. You'll need to use the `--root-dir` flag if that's not the case. -[/info] +> [!NOTE] +> Sample upgrader commands in this guide assume your working directory is the root of your Silverstripe CMS project. You'll need to use the `--root-dir` flag if that's not the case. #### Install the upgrader globally with composer @@ -938,9 +936,8 @@ class ProductService } ``` -[warning] -Avoid using `static::class` or `parent::class` to retrieve translated string. It will retrieve unpredictable values bases on the class inheritance. -[/warning] +> [!WARNING] +> Avoid using `static::class` or `parent::class` to retrieve translated string. It will retrieve unpredictable values bases on the class inheritance. If your template files contain translatable strings, they also need to be updated to referenced the namespaced classes. For example, `<%t Member.SINGULARNAME 'Member' %>` would become `<%t SilverStripe\Security\Member.SINGULARNAME 'Member' %>`. diff --git a/en/03_Upgrading/06_Upgrading_to_GraphQL_4.md b/en/03_Upgrading/06_Upgrading_to_GraphQL_4.md index fb325c25f..d626316f8 100644 --- a/en/03_Upgrading/06_Upgrading_to_GraphQL_4.md +++ b/en/03_Upgrading/06_Upgrading_to_GraphQL_4.md @@ -5,11 +5,10 @@ summary: Upgrade your Silverstripe CMS project to use graphQL version 4 # Upgrading to GraphQL 4 -[info] -You are viewing docs for silverstripe/graphql 4.x. -If you are using 3.x, documentation can be found -[in the GitHub repository](https://github.com/silverstripe/silverstripe-graphql/tree/3) -[/info] +> [!NOTE] +> You are viewing docs for silverstripe/graphql 4.x. +> If you are using 3.x, documentation can be found +> [in the GitHub repository](https://github.com/silverstripe/silverstripe-graphql/tree/3) The 4.0 release of `silverstripe/graphql` underwent a massive set of changes representing an entire rewrite of the module. This was done as part of a year-long plan to improve performance. While @@ -244,11 +243,10 @@ class MyProvider implements SchemaUpdater } ``` -[alert] -The API for procedural code has been **completely rewritten**. You'll need to rewrite all of the code -in these classes. For more information on working with procedural code, read the -[using procedural code](/developer_guides/graphql/getting_started/using_procedural_code) documentation. -[/alert] +> [!CAUTION] +> The API for procedural code has been **completely rewritten**. You'll need to rewrite all of the code +> in these classes. For more information on working with procedural code, read the +> [using procedural code](/developer_guides/graphql/getting_started/using_procedural_code) documentation. ## Goodbye scaffolding, hello models @@ -377,13 +375,12 @@ Change any references to DataObject type names in your queries `query SiteTrees {}` -[info] -If this new pattern is not compatible with your set up (e.g. if you use feature-based namespacing), you have full -control over how types are named. You can use the `type_formatter` and `type_prefix` on -[`DataObjectModel`](api:SilverStripe\GraphQL\Schema\DataObject\DataObjectModel) to influence the naming computation. -Read more about this in the [DataObject model type](/developer_guides/graphql/getting_started/working_with_dataobjects/dataobject_model_type#customising-the-type-name) -docs. -[/info] +> [!NOTE] +> If this new pattern is not compatible with your set up (e.g. if you use feature-based namespacing), you have full +> control over how types are named. You can use the `type_formatter` and `type_prefix` on +> [`DataObjectModel`](api:SilverStripe\GraphQL\Schema\DataObject\DataObjectModel) to influence the naming computation. +> Read more about this in the [DataObject model type](/developer_guides/graphql/getting_started/working_with_dataobjects/dataobject_model_type#customising-the-type-name) +> docs. ## The `Connection` class has been replaced with plugins diff --git a/en/03_Upgrading/07_Deprecations.md b/en/03_Upgrading/07_Deprecations.md index 65e3aecff..a0ef68f94 100644 --- a/en/03_Upgrading/07_Deprecations.md +++ b/en/03_Upgrading/07_Deprecations.md @@ -15,9 +15,8 @@ Major releases of Silverstripe CMS introduce many API changes. They include a de To enable deprecation warnings, set the `SS_DEPRECATION_ENABLED` environment variable in your project's `.env` file. -[info] -If the `SS_DEPRECATION_ENABLED` environment variable is set, this takes precedence over use of the `Deprecation::enable()` static method. -[/info] +> [!NOTE] +> If the `SS_DEPRECATION_ENABLED` environment variable is set, this takes precedence over use of the `Deprecation::enable()` static method. ```bash SS_DEPRECATION_ENABLED=true @@ -29,9 +28,8 @@ Alternatively, add the following line to your project's `app/_config.php`. Deprecation::enable(); ``` -[info] -Deprecation warnings will only ever show if your `SS_ENVIRONMENT_TYPE` is set to `dev`. -[/info] +> [!NOTE] +> Deprecation warnings will only ever show if your `SS_ENVIRONMENT_TYPE` is set to `dev`. Once you have resolved all of the deprecation warnings you can, it is recommended to turn off deprecation warnings again. @@ -63,17 +61,16 @@ SilverStripe\Core\Injector\Injector: ErrorLogFileHandler: [ pushHandler, [ '%$ErrorLogFileHandler' ] ] ``` -[notice] -The log file path must be an absolute file path, as relative paths may behave differently between CLI and HTTP requests. If you want to use a *relative* path, you can use the `SS_ERROR_LOG` environment variable to declare a file path that is relative to your project root: - -```bash -SS_ERROR_LOG="./silverstripe.log" -``` - -You don't need any of the YAML configuration above if you are using the `SS_ERROR_LOG` environment variable - but you can use a combination of the environment variable and YAML configuration if you want to configure multiple error log files. - -You will also need to make sure the user running the PHP process has write access to the log file, wherever you choose to put it. -[/notice] +> [!WARNING] +> The log file path must be an absolute file path, as relative paths may behave differently between CLI and HTTP requests. If you want to use a *relative* path, you can use the `SS_ERROR_LOG` environment variable to declare a file path that is relative to your project root: +> +> ```bash +> SS_ERROR_LOG="./silverstripe.log" +> ``` +> +> You don't need any of the YAML configuration above if you are using the `SS_ERROR_LOG` environment variable - but you can use a combination of the environment variable and YAML configuration if you want to configure multiple error log files. +> +> You will also need to make sure the user running the PHP process has write access to the log file, wherever you choose to put it. See [Configuring error logging](/developer_guides/debugging/error_handling/#configuring-error-logging) to learn about other ways you can handle error logs. @@ -83,9 +80,8 @@ Deprecation warnings won't be output to HTTP responses by default because it can Deprecation warnings can be set to output in HTTP responses by setting `SS_DEPRECATION_SHOW_HTTP` to a truthy value in your .env file. -[info] -If the `SS_DEPRECATION_SHOW_HTTP` environment variable is set, this takes precedence over use of the `Deprecation::setShouldShowForHttp()` static method. -[/info] +> [!NOTE] +> If the `SS_DEPRECATION_SHOW_HTTP` environment variable is set, this takes precedence over use of the `Deprecation::setShouldShowForHttp()` static method. ```bash SS_DEPRECATION_SHOW_HTTP=true @@ -99,9 +95,8 @@ Deprecation::setShouldShowForHttp(true); Note that the output for this won't be very easy to read. You might prefer instead to install [lekoala/silverstripe-debugbar](https://github.com/lekoala/silverstripe-debugbar) as a dev dependency. Deprecation warnings will be logged in the "messages" tab of the debugbar. -[warning] -The debugbar will *not* show you any deprecation warnings that are triggered from XHR/AJAX requests or which are triggered after the middleware has finished generating the debugbar for the response. -[/warning] +> [!WARNING] +> The debugbar will *not* show you any deprecation warnings that are triggered from XHR/AJAX requests or which are triggered after the middleware has finished generating the debugbar for the response. ## Deprecation warnings in the CLI @@ -109,9 +104,8 @@ Deprecation warnings are output for CLI responses by default (assuming they're e You can suppress deprecation warnings from CLI output by setting `SS_DEPRECATION_SHOW_CLI` to a falsy value in your .env file. -[info] -If the `SS_DEPRECATION_SHOW_CLI` environment variable is set, this takes precedence over use of the `Deprecation::SS_DEPRECATION_SHOW_CLI()` static method. -[/info] +> [!NOTE] +> If the `SS_DEPRECATION_SHOW_CLI` environment variable is set, this takes precedence over use of the `Deprecation::SS_DEPRECATION_SHOW_CLI()` static method. ```bash SS_DEPRECATION_SHOW_CLI=false diff --git a/en/03_Upgrading/07_Upgrading_Fluent.md b/en/03_Upgrading/07_Upgrading_Fluent.md index fd1978a37..e09da6444 100644 --- a/en/03_Upgrading/07_Upgrading_Fluent.md +++ b/en/03_Upgrading/07_Upgrading_Fluent.md @@ -58,9 +58,8 @@ Locale fallback logic and options have changed significantly. In Fluent v5, the `DataObject.cms_publish_required` configuration property was renamed to `DataObject.cms_localisation_required`. -[info] -If you have set `cms_publish_required` configuration in your YAML configuration files, `Extension` class, or `DataObject` models, change these to `cms_localisation_required` instead. -[/info] +> [!NOTE] +> If you have set `cms_publish_required` configuration in your YAML configuration files, `Extension` class, or `DataObject` models, change these to `cms_localisation_required` instead. #### Fallback changes in fluent v6 {#locale-fallback-v6} @@ -68,9 +67,8 @@ The values for the `DataObject.frontend_publish_required` and `DataObject.cms_lo If you had set either property to `true` in previous versions, this is the equivalent of the new "exact" value, where `false` is the equivalent of "any". -[hint] -If you're setting these values in an extension or model with the private static properties, you can use the constants from `FluentExtension` (e.g. `FluentExtension::INHERITANCE_MODE_EXACT`). -[/hint] +> [!TIP] +> If you're setting these values in an extension or model with the private static properties, you can use the constants from `FluentExtension` (e.g. `FluentExtension::INHERITANCE_MODE_EXACT`). | | `frontend_publish_required` | `cms_localisation_required` | |-------------|--------------------------------|-------------------------------| @@ -83,9 +81,8 @@ Here's what the new values actually mean: |-----|-----|-----| | Content for this record must exist in any locale *or the base (unlocalised) record*. | Content for this record must exist in the current locale *or* a specific fallback locale, as defined through the Locales admin section. | Content for this record *must* exist in the current locale to be used. | -[notice] -Review localisation settings on all of your models and migrate to the correct value. *Do not* just swap to the new equivalent of your old value unless you explicitly want to keep that behaviour. Instead, consider whether the new functionality warrants a change to a different option. -[/notice] +> [!WARNING] +> Review localisation settings on all of your models and migrate to the correct value. *Do not* just swap to the new equivalent of your old value unless you explicitly want to keep that behaviour. Instead, consider whether the new functionality warrants a change to a different option. ### User permissions @@ -95,9 +92,8 @@ Fluent v5 introduced more granular permission management. |---------------------------|--------------|--------------|--------------| | Locale permission support | No | Yes | Yes | -[hint] -If you're upgrading from Fluent v4, review your requirements for user permissions in the context of locales and update the permissions as needed. For example you may have content authors who should only be allowed to edit content for specific locales. -[/hint] +> [!TIP] +> If you're upgrading from Fluent v4, review your requirements for user permissions in the context of locales and update the permissions as needed. For example you may have content authors who should only be allowed to edit content for specific locales. ### Enhanced CMS UI @@ -112,9 +108,8 @@ As mentioned in the table above, the `batch_actions_enabled` configuration value ![The "Localisation" action group, expanded to show all the actions available in it](../_images/fluent/batch_actions_enabled.png) -[hint] -Review available CMS UI components and enable those that you need. -[/hint] +> [!TIP] +> Review available CMS UI components and enable those that you need. ## Localised version history @@ -173,12 +168,11 @@ $model->isPublished(); $model->isPublishedInLocale(); ``` -[/warning] -It's common for Fluent 4 projects to have a lot of custom code to -achieve the same result as this feature. Any such custom code needs to be -identified and removed as a part of the upgrade as it's likely going to -clash with this feature. -[/warning] +> [!WARNING] +> It's common for Fluent 4 projects to have a lot of custom code to +> achieve the same result as this feature. Any such custom code needs to be +> identified and removed as a part of the upgrade as it's likely going to +> clash with this feature. ## Localised relations @@ -215,9 +209,8 @@ class HomePage extends Page } ``` -[note] -You cannot simply localise the `BannerID` field and expect the relation to be localised, as that won't copy the `Banner` object to the new locale. -[/note] +> [!NOTE] +> You cannot simply localise the `BannerID` field and expect the relation to be localised, as that won't copy the `Banner` object to the new locale. This strategy is called "localise by relation" AKA "indirect localisation". We recommend this approach in most cases. diff --git a/en/04_Changelogs/4.11.0.md b/en/04_Changelogs/4.11.0.md index 0395a2de2..e8a6f88cc 100644 --- a/en/04_Changelogs/4.11.0.md +++ b/en/04_Changelogs/4.11.0.md @@ -276,9 +276,8 @@ SilverStripe\Security\Member: notify_password_change: false ``` -[info] -Note that this configuration is already enabled by default in the `cwp/cwp-core` module. Projects which have that as a dependency won't experience any change in behaviour. -[/info] +> [!NOTE] +> Note that this configuration is already enabled by default in the `cwp/cwp-core` module. Projects which have that as a dependency won't experience any change in behaviour. The email content can also be changed in a couple of ways: diff --git a/en/04_Changelogs/4.4.0.md b/en/04_Changelogs/4.4.0.md index f86807ec4..d40de1a4f 100644 --- a/en/04_Changelogs/4.4.0.md +++ b/en/04_Changelogs/4.4.0.md @@ -369,17 +369,16 @@ version generates its own manifest cache. However, if that's not the case, you m time with cache generation timestamp. This effectively eliminates the possibility for the manifest cache to be incompatible with the deployed app. -[alert] -WARNING! If you do not deploy your application as a whole, but rather update its files in place with `rsync`, `ssh` -or `FTP`, you should consider triggering CLI based `flush` manually on every such deploy (e.g. with sake). -Otherwise, you may end up with your application cache to be incompatible with its source code, which would make things -broken. There is a tiny possibility that you wouldn't even be able to flush through browser in that case. -
-In that case you may consider using `SS_FLUSH_ON_DEPLOY`. Depending on your deployment tooling you may point it to a filesystem resource -that gets modified on every deploy update so that the framework will automatically perform `flush` for you. -
-The best practice is not to reuse the application manifest cache between deploys. -[/alert] +> [!CAUTION] +> WARNING! If you do not deploy your application as a whole, but rather update its files in place with `rsync`, `ssh` +> or `FTP`, you should consider triggering CLI based `flush` manually on every such deploy (e.g. with sake). +> Otherwise, you may end up with your application cache to be incompatible with its source code, which would make things +> broken. There is a tiny possibility that you wouldn't even be able to flush through browser in that case. +>
+> In that case you may consider using `SS_FLUSH_ON_DEPLOY`. Depending on your deployment tooling you may point it to a filesystem resource +> that gets modified on every deploy update so that the framework will automatically perform `flush` for you. +>
+> The best practice is not to reuse the application manifest cache between deploys. ### New `GridField` detail form actions {#better-buttons} diff --git a/en/05_Contributing/00_Issues_and_Bugs.md b/en/05_Contributing/00_Issues_and_Bugs.md index b4e2ef2c6..8cb176c08 100644 --- a/en/05_Contributing/00_Issues_and_Bugs.md +++ b/en/05_Contributing/00_Issues_and_Bugs.md @@ -8,9 +8,8 @@ icon: bug ## Reporting bugs -[alert] -If you think you've found a security issue, please use [the specific process](#reporting-security-issues) for those. Do *not* raise a security issue in GitHub. -[/alert] +> [!CAUTION] +> If you think you've found a security issue, please use [the specific process](#reporting-security-issues) for those. Do *not* raise a security issue in GitHub. If you have discovered a bug in Silverstripe CMS, we'd be glad to hear about it - well written bug reports can be half of the solution already! @@ -19,9 +18,8 @@ Silverstripe CMS uses [GitHub](https://github.com/) to manage bug reports. If yo want to report a bug, you will need to [create a GitHub account](https://docs.github.com/en/get-started/onboarding/getting-started-with-your-github-account) and log in. -[warning] -We don't provide support through GitHub issues. If you're having trouble using or developing with Silverstripe CMS but you don't think your problem is a bug, please ask for assistance in our [community channels](https://www.silverstripe.org/community). -[/warning] +> [!WARNING] +> We don't provide support through GitHub issues. If you're having trouble using or developing with Silverstripe CMS but you don't think your problem is a bug, please ask for assistance in our [community channels](https://www.silverstripe.org/community). ### Before submitting a bug @@ -54,22 +52,20 @@ is the best way to ensure it gets fixed. ## Feature requests -[warning] -Please don't file feature requests as GitHub issues. If there's a new feature -you'd like to see in Silverstripe CMS, you either need to write it yourself (and -[submit a pull request](/contributing/code/#step-by-step-from-forking-to-sending-the-pull-request)) or convince somebody else to -write it for you. Any "wishlist" type issues without code attached can be -expected to be closed as soon as they're reviewed. -[/warning] +> [!WARNING] +> Please don't file feature requests as GitHub issues. If there's a new feature +> you'd like to see in Silverstripe CMS, you either need to write it yourself (and +> [submit a pull request](/contributing/code/#step-by-step-from-forking-to-sending-the-pull-request)) or convince somebody else to +> write it for you. Any "wishlist" type issues without code attached can be +> expected to be closed as soon as they're reviewed. In order to gain interest and feedback in your feature, we encourage you to present it to the community through the [community channels](https://www.silverstripe.org/community). ## Reporting security issues -[warning] -If you think a bug may have security implications, do not create a GitHub issue for it. This may lead to a zero-day vulnerability. -[/warning] +> [!WARNING] +> If you think a bug may have security implications, do not create a GitHub issue for it. This may lead to a zero-day vulnerability. Report potential security issues to [security@silverstripe.org](mailto:security@silverstripe.org). Emails sent to that address are forwarded to a private mailing list and kick off a specific security process. diff --git a/en/05_Contributing/01_Code.md b/en/05_Contributing/01_Code.md index 059cd9cfa..ea2c46424 100644 --- a/en/05_Contributing/01_Code.md +++ b/en/05_Contributing/01_Code.md @@ -10,19 +10,17 @@ The Silverstripe CMS core and supported modules are hosted on [GitHub](https://g This documentation assumes you are fairly confident with git and GitHub. If that isn't the case, you may want to read some guides for [GitHub](https://docs.github.com/en/get-started/quickstart), [git](https://docs.github.com/en/get-started/using-git), and [pull requests](https://docs.github.com/en/pull-requests). -[hint] -Note: By supplying code to the Silverstripe CMS core team in issues and pull requests, you agree to assign copyright of that code to Silverstripe Limited, on the condition that Silverstripe Limited releases that code under the BSD license. - -We ask for this so that the ownership in the license is clear and unambiguous, and so that community involvement doesn't stop us from being able to continue supporting these projects. By releasing this code under a permissive license, this copyright assignment won't prevent you from using the code in any way you see fit. -[/hint] +> [!TIP] +> Note: By supplying code to the Silverstripe CMS core team in issues and pull requests, you agree to assign copyright of that code to Silverstripe Limited, on the condition that Silverstripe Limited releases that code under the BSD license. +> +> We ask for this so that the ownership in the license is clear and unambiguous, and so that community involvement doesn't stop us from being able to continue supporting these projects. By releasing this code under a permissive license, this copyright assignment won't prevent you from using the code in any way you see fit. ## Before you start working {#before-you-start} There are a few things that you should do before you start working on a fix: -[info] -If you want to contribute changes to documentation, please read through the [contributing documentation](./documentation) page. -[/info] +> [!NOTE] +> If you want to contribute changes to documentation, please read through the [contributing documentation](./documentation) page. ### Consider if your change should be its own module @@ -46,11 +44,10 @@ Refer to [Contributing Issues](./issues_and_bugs/) for more information about fi ## Step-by-step: how to contribute code {#step-by-step} -[notice] -The examples below assume you are making a change that applies to the `4.13` branch. - -Please adjust the commands as appropriate for the version of Silverstripe CMS that you're targeting. See [picking the right version](#picking-the-right-version). -[/notice] +> [!WARNING] +> The examples below assume you are making a change that applies to the `4.13` branch. +> +> Please adjust the commands as appropriate for the version of Silverstripe CMS that you're targeting. See [picking the right version](#picking-the-right-version). ### Editing files directly on GitHub @@ -71,9 +68,8 @@ As we follow semantic versioning, we name the branches in repositories according If after reading this section you are still unsure what branch your pull request should go to, consider asking either in the GitHub issue that you address with your PR or in one of the various [community channels](https://www.silverstripe.org/community/). -[hint] -Refer to our [definition of public API](/project_governance/public_api/) for the following sections. -[/hint] +> [!TIP] +> Refer to our [definition of public API](/project_governance/public_api/) for the following sections. Any updates to third party dependencies in `composer.json` should aim to target the default branch for a minor release if possible. Targeting a patch release branch is acceptable if updating dependencies is required to fix a high impact or critical bug and is unlikely to result in regressions. @@ -129,9 +125,8 @@ composer reinstall / --prefer-source git checkout -b ``` -[hint] -Use a descriptive name for your branch. For example if you are fixing a bug related to swapping preview modes targetting the `4.13` branch: `pulls/4.13/fix-preview-modes` -[/hint] +> [!TIP] +> Use a descriptive name for your branch. For example if you are fixing a bug related to swapping preview modes targetting the `4.13` branch: `pulls/4.13/fix-preview-modes` ### Step 4: work on your pull request {#work-on-your-pr} @@ -226,9 +221,8 @@ The core team will review the pull request as time permits. They will most likel If other changes are merged in before yours, your pull request may end up with merge conflicts. You'll need to resolve those by rebasing your branch on top of the target branch, and then manually resolving the merge conflicts. -[warning] -Using `--force-with-lease` is necessary after a rebase, because otherwise GitHub will reject your push. This is because your commit hashes will have changed. But beware that you are explicitly telling GitHub that you are intentionally overriding data. Make sure you have the correct branch name when doing that step to avoid accidentally overriding other branches in your forked repository. -[/warning] +> [!WARNING] +> Using `--force-with-lease` is necessary after a rebase, because otherwise GitHub will reject your push. This is because your commit hashes will have changed. But beware that you are explicitly telling GitHub that you are intentionally overriding data. Make sure you have the correct branch name when doing that step to avoid accidentally overriding other branches in your forked repository. ```bash cd vendor// diff --git a/en/05_Contributing/02_Documentation.md b/en/05_Contributing/02_Documentation.md index adc312f40..0f4bcf7a0 100644 --- a/en/05_Contributing/02_Documentation.md +++ b/en/05_Contributing/02_Documentation.md @@ -30,9 +30,8 @@ If you find a problem related to how the documentation is displayed which can't - If you are fixing incorrect or incomplete information, you should create a PR that targets the most recent patch release branch branch for the relevant major release line (e.g. `4.13`). - If you are adding documentation for functionality that has not yet been released, you should target the most recent minor release branch branch (e.g. `5`). -[warning] -You should make your changes in the lowest major branch they apply to. For instance, if you fix a spelling issue that you found in the CMS 4 documentation, submit your fix to the `4.13` branch in GitHub and it'll be copied to the most recent major version of the documentation automatically. *Don't submit multiple pull requests for the same change*. -[/warning] +> [!WARNING] +> You should make your changes in the lowest major branch they apply to. For instance, if you fix a spelling issue that you found in the CMS 4 documentation, submit your fix to the `4.13` branch in GitHub and it'll be copied to the most recent major version of the documentation automatically. *Don't submit multiple pull requests for the same change*. ## Editing online @@ -129,52 +128,46 @@ Silverstripe CMS documentation has a few special syntax extensions that normal m There are several built-in block styles for calling out a paragraph of text. Please use these graphical elements sparingly. -[info] -"Info box": An info box is useful for adding, deepening or accenting information in the main text. They can be used for background knowledge, or to provide links to further information (ie, a "see also" link). -[/info] +These callout blocks are compatible with [GitHub markdown alerts](https://docs.github.com/en/get-started/writing-on-github/getting-started-with-writing-and-formatting-on-github/basic-writing-and-formatting-syntax#alerts), so they'll display correctly both on this website as well as in GitHub directly. -Code for an Info box: +> [!NOTE] +> "Note box": A note box is useful for adding, deepening or accenting information in the main text. They can be used for background knowledge, or to provide links to further information (ie, a "see also" link). + +Code for a note box: ```text -[info] -... -[/info] +> [!NOTE] +> ... ``` -[hint] -"Hint box": A hint box is great for pointing out extra use cases or hints about how to use a feature. -[/hint] +> [!TIP] +> "Tip box": A tip box is great for pointing out extra use cases or tips about how to use a feature. -Code for a Hint box: +Code for a tip box: ```text -[hint] -... -[/hint] +> [!TIP] +> ... ``` -[warning] -"Warning box": A warning box is useful for pointing out gotchas or technical notifications relating to the main text. For example, notifying users about a deprecated feature. -[/warning] +> [!WARNING] +> "Warning box": A warning box is useful for pointing out gotchas or technical notifications relating to the main text. For example, notifying users about a deprecated feature. Code for a Warning box: ```text -[warning] -... -[/warning] +> [!WARNING] +> ... ``` -[alert] -"Alert box": An alert box is good for for calling out a severe bug or a technical issue requiring a user's attention. For example, suppose a rare edge case sometimes leads to a variable being overwritten incorrectly. An alert box can be used to alert the user to this case so they can write their own code to handle it. -[/alert] +> [!CAUTION] +> Caution box": A caution box is good for for calling out a severe bug or a technical issue requiring a user's attention. For example, suppose a rare edge case sometimes leads to a variable being overwritten incorrectly. A caution box can be used to alert the user to this case so they can write their own code to handle it. -Code for an Alert box: +Code for a caution box: ```text -[alert] -... -[/alert] +> [!CAUTION] +> ... ``` ### Links to documentation diff --git a/en/05_Contributing/06_Build_Tooling.md b/en/05_Contributing/06_Build_Tooling.md index 381a6d75a..0de53855c 100644 --- a/en/05_Contributing/06_Build_Tooling.md +++ b/en/05_Contributing/06_Build_Tooling.md @@ -44,14 +44,13 @@ Once you've installed Node.js and yarn, run the following command once in the `s yarn install ``` -[notice] -The `silverstripe/admin` repository includes some components and dependencies that other modules -need to work. Make sure that in addition to the module(s) who's code you're touching, you also run -`yarn install` in the directory for `silverstripe/admin`. - -You may need to first run `composer reinstall silverstripe/admin --prefer-source` if you installed -that module without `--prefer-source` originally. -[/notice] +> [!WARNING] +> The `silverstripe/admin` repository includes some components and dependencies that other modules +> need to work. Make sure that in addition to the module(s) who's code you're touching, you also run +> `yarn install` in the directory for `silverstripe/admin`. +> +> You may need to first run `composer reinstall silverstripe/admin --prefer-source` if you installed +> that module without `--prefer-source` originally. ## Build commands diff --git a/en/05_Contributing/08_Triage_Resources.md b/en/05_Contributing/08_Triage_Resources.md index cb73dc60d..9a7f99112 100644 --- a/en/05_Contributing/08_Triage_Resources.md +++ b/en/05_Contributing/08_Triage_Resources.md @@ -12,9 +12,8 @@ If you are involved with triage of Silverstripe CMS core and supported modules, You can also optionally subscribe to the repository via [GitHub watch functionality](https://docs.github.com/en/account-and-profile/managing-subscriptions-and-notifications-on-github/setting-up-notifications/configuring-notifications#configuring-your-watch-settings-for-an-individual-repository). -[hint] -When performing these tasks, make sure to adhere to the [code of conduct](/project_governance/code_of_conduct/) and [maintainer guidelines](/project_governance/maintainer_guidelines/#guidelines). -[/hint] +> [!TIP] +> When performing these tasks, make sure to adhere to the [code of conduct](/project_governance/code_of_conduct/) and [maintainer guidelines](/project_governance/maintainer_guidelines/#guidelines). ## How to triage diff --git a/en/05_Contributing/10_Managing_Security_Issues.md b/en/05_Contributing/10_Managing_Security_Issues.md index 296b85565..f39877a88 100644 --- a/en/05_Contributing/10_Managing_Security_Issues.md +++ b/en/05_Contributing/10_Managing_Security_Issues.md @@ -28,9 +28,8 @@ This process is usually started once someone [reports a security issue](issues_a ### When receiving a report -[hint] -Ensure the reporter is given a justification for all issues we conclude are not security vulnerabilities. -[/hint] +> [!TIP] +> Ensure the reporter is given a justification for all issues we conclude are not security vulnerabilities. 1. An automated response is sent back to the reporter to acknowledge receipt of their vulnerability report. 1. Perform an initial assessment of the report. If the report does not qualify as a security issue, reply to the reporter thanking them for their efforts and explaining that we won't be handling this as a security issue. @@ -55,9 +54,8 @@ Ensure the reporter is given a justification for all issues we conclude are not 1. Once a CVE has been assigned, add it to the GitHub issue and respond to the issue reporter. - Ask the reporter if they want to be credited for the disclosure and under what name. -[warning] -Make sure you read the [special circumstances](#special-circumstances) section below in case there are more or different steps you need to follow. -[/warning] +> [!WARNING] +> Make sure you read the [special circumstances](#special-circumstances) section below in case there are more or different steps you need to follow. ### Creating a GitHub security advisory diff --git a/en/06_Project_Governance/03_Maintainer_Guidelines.md b/en/06_Project_Governance/03_Maintainer_Guidelines.md index 6bfc96791..5a00a4598 100644 --- a/en/06_Project_Governance/03_Maintainer_Guidelines.md +++ b/en/06_Project_Governance/03_Maintainer_Guidelines.md @@ -10,10 +10,9 @@ The maintainer guidelines apply to [supported modules](./supported_modules/). Un This document outlines expectations on maintainers of Silverstripe CMS. It also forms the default expectations for maintainers of [supported modules](./supported_modules/), unless more specific contribution guidelines are available for a module. -[note] -A lot of extra information is available in the [Contributing](/contributing/) documentation. -All maintainers should be familiar with those docs as they explain many details about how we work. -[/note] +> [!NOTE] +> A lot of extra information is available in the [Contributing](/contributing/) documentation. +> All maintainers should be familiar with those docs as they explain many details about how we work. Refer to the [triage and peer review](/contributing/triage_resources/) for information about how those tasks are performed. @@ -52,9 +51,8 @@ CMS Squad members have write access to core repositories in order to work effect ### Peer reviewers -[info] -This is a new role, and is currently in a trial period. It is likely to change over time as we learn what works and what doesn't. -[/info] +> [!NOTE] +> This is a new role, and is currently in a trial period. It is likely to change over time as we learn what works and what doesn't. This role is made up of community members who have demonstrated a willingness and ability to improve Silverstripe CMS through their contributions to the open source supported modules. It empowers community members to have a more active role in ensuring pull requests get merged, and builds more momentum for community-created pull requests. @@ -106,9 +104,8 @@ There will be a low-touch background check before inviting the contributor to th ### Contribution refiners -[info] -This is a new role, and is currently in a trial period. It is likely to change over time as we learn what works and what doesn't. -[/info] +> [!NOTE] +> This is a new role, and is currently in a trial period. It is likely to change over time as we learn what works and what doesn't. This role is made up of community members who have demonstrated a willingness and ability to improve Silverstripe CMS through their contributions to the open source supported modules. It empowers community members to have a more active role in identifying and refining bug reports and pull requests with high value potential so that they can be resolved more quickly. diff --git a/en/06_Project_Governance/05_Major_release_policy.md b/en/06_Project_Governance/05_Major_release_policy.md index 7a0329011..fb31c16b1 100644 --- a/en/06_Project_Governance/05_Major_release_policy.md +++ b/en/06_Project_Governance/05_Major_release_policy.md @@ -12,9 +12,8 @@ This policy applies to all [Silverstripe CMS commercially supported modules](htt Community modules are not covered by this policy. Modules in the `silverstripe` GitHub organisation that are not commercially supported are updated on a best effort basis. -[info] -Refer to our [definition of public API](/project_governance/public_api/). -[/info] +> [!NOTE] +> Refer to our [definition of public API](/project_governance/public_api/). ## General approach to major releases diff --git a/en/06_Project_Governance/06_Minor_release_policy.md b/en/06_Project_Governance/06_Minor_release_policy.md index 2434109d8..169bed327 100644 --- a/en/06_Project_Governance/06_Minor_release_policy.md +++ b/en/06_Project_Governance/06_Minor_release_policy.md @@ -12,9 +12,8 @@ Note that the release cadence and pre-release time frame are indicative only. We Our minor release policy is more flexible because minor release upgrades are more straightforward to manage than major release upgrades. -[info] -Refer to our [definition of public API](/project_governance/public_api/). -[/info] +> [!NOTE] +> Refer to our [definition of public API](/project_governance/public_api/). ## Scope of the policy