First pass at upgrade docs

This commit is contained in:
Aaron Carlino 2017-07-13 14:57:28 +12:00 committed by Daniel Hensby
parent d7095c2213
commit 2b9369895d
No known key found for this signature in database
GPG Key ID: B00D1E9767F0B06E

View File

@ -59,6 +59,7 @@ guide developers in preparing existing 3.x code for compatibility with 4.0
[behat extension](https://github.com/silverstripe/silverstripe-behat-extension) for more information.
* The `GDBackend` and `ImagickBackend` classes have been replaced by a unified `InterventionBackend` which uses the
[intervention/image](https://github.com/intervention/image) library to power manipualations.
* Page types and their controllers can no longer be collated in a single file
## <a name="upgrading"></a>Upgrading
@ -92,6 +93,138 @@ For a full list of renamed classes, check the `.upgrade.yml` definitions in each
The rename won't affect class-based permission codes or database table names.
##### Use ::class whenever possible
Prefer:
```php
private static $has_one = [
'MyObject' => MyObject::class
];
```
to
```php
private static $has_one = [
'MyObject' => 'My\Project\MyObject'
];
```
##### Use Injector wherever you can
This can help with reducing changes from 3.x to 4.x by allowing your code to
continue to use `MyClassName`, while you tell the injector what the FQ class name is:
```yaml
SilverStripe\Core\Injector\Injector:
MyClassName:
class: Me\MyModule\MyClassName # fully qualified!
```
##### Namespaced table names
Keep in mind that table names are namespaced too. To ease data migrations, use the `$table_name` config property of your `DataObject` subclasses.
This allows you to customise the table name to something simpler, or perhaps identical to its 3.x name.
```php
namespace SilverStripe\BannerManager;
use SilverStripe\ORM\DataObject;
class BannerImage extends DataObject
{
private static $table_name = 'BannerImage';
}
```
In order to ensure you are using the correct table for any class a new [DataObjectSchema](api:SilverStripe\ORM\DataObjectSchema) service
is available to manage these mappings (see [versioned documentation](/developer_guides/model/data_model_and_orm)).
```php
public function countDuplicates($model, $fieldToCheck)
{
$table = SilverStripe\ORM\DataObject::getSchema()->tableForField($model, $field);
$query = new SilverStripe\ORM\Queries\SQLSelect();
$query->setFrom("\"{$table}\"");
$query->setWhere(["\"{$table}\".\"{$field}\"" => $model->$fieldToCheck]);
return $query->count();
}
```
##### Class name remapping
If you've namespaced one of your custom page types then loaded up the CMS and see
a message telling you it's obsolete. This is likely because the `ClassName`
field in the `SiteTree` table still contains the singular model name, e.g. `BlogPost`
and that when you change it to `SilverStripe\Blog\Model\BlogPost` then everything
works again.
Luckily the `dev/build` task is configured to look for a legacy class name mapping
configuration setting and will update this for you automatically. For an example
take a look at `_config/legacy.yml` in the CMS module. For the Blog module we used
this:
```yaml
SilverStripe\ORM\DatabaseAdmin:
classname_value_remapping:
Blog: SilverStripe\Blog\Model\Blog
BlogCategory: SilverStripe\Blog\Model\BlogCategory
BlogPost: SilverStripe\Blog\Model\BlogPost
BlogTag: SilverStripe\Blog\Model\BlogTag
```
##### Other namespacing gotchas
You'll need to update any strings that represent class names and make sure they're fully
qualified. In particular, relationship definitions such as `has_one` and `has_many` will need
to be updated to refer to fully qualified class names.
```ss
<!-- before -->
private static $has_one = [
'MyRelation' => 'MyObject',
];
<!-- after -->
private static $has_one = [
'MyRelation' => MyObject::class,
];
```
In the context of YAML, the magic constant `::class` does not apply. Class names must be hard coded.
```ss
<!-- before -->
MyObject:
property: value
<!-- after -->
My\Project\MyObject:
property: value
```
When dealing with custom database queries, you need to be judicious about replacing table
names expressed literally. The upgrader will automatically replace anything that looks
like an unqualified class name with a fully qualified one, but a fully qualified
class name may not be the same as the table name, as explained above, in the case of
`$table_name`.
For example:
```php
->innerJoin('BlogPost', sprintf('"BlogPost%s"."ID" = "SiteTree%s"."ID"', $stage, $stage))
```
The upgrader will replace `BlogPost` with `SilverStripe\\Blog\\Model\BlogPost` as the fully qualified class name. In the case of innerJoin(), it asks for a table name which have remained the same as SilverStripe 3.x, so this should not be namespaced. This of course depends on what youve configured your table name to be.
A better option is to replace it with `DataObject::getSchema()->tableName(BlogPost::class)` as long as the class has already been imported into your current namespace.
#### Migrate your controllers to their own files
The convention for naming controllers is now `[MyPageType]Controller`, where it used to be `[MyPageType]_Controller`. This change was made to be more compatible with the PSR-2 standards.
You can still use, for example, `Page_Controller`, but you will get a deprecation notice. Best to change it to `PageController` during your upgrade process.
By default, a controller for a page type *must* reside in the same namespace as its page. To break this convention, override `SiteTree::getControllerName()`.
#### Upgrade template locations and references
Templates are now much more strict about their locations. You can no longer put a template in an arbitrary
@ -109,6 +242,106 @@ Core template locations have moved - if you're including or overriding these
no longer exists, and instead template locations will be placed in paths that match
the `SilverStripe\Forms` namespace.
#### Upgrade your member statics
If you've got some class configuration statics defined and they aren't private,
you may find that they don't register any more. For example, this code, taken from
the `silverstripe/tagfield` module will no longer work in SilverStripe 4.0.
```php
public static $allowed_actions = [
'suggest'
];
```
Changing the visibility to `private` (as per `RequestHandler::$allowed_actions`
visibility) will make it 4.0 compatible.
```ss
<!-- before -->
public static $allowed_actions = [
'suggest'
];
<!-- after -->
private static $allowed_actions = [
'suggest'
];
```
#### Get on board with PSR-4 autoloading
While not critical to an upgrade, SilverStripe 4.0 has adopted the [PS-4 autoloading](http://www.php-fig.org/psr/psr-4/)
standard for the core modules, so it's probably a good idea to be consistent.
You can implement this into your composer configuration like so:
```js
...
"autoload": {
"psr-4": {
"SilverStripe\\Blog\\": "src/"
}
},
...
```
Now you just need to ensure that each class site in the correct folder location
(including case sensitivity) to match its namespace. For example,
`SilverStripe\Blog\Model\BlogPost` should live at `src/Model/BlogPost.php`.
Note that you dont have to use `src/` as the root folder name. You can continue
to use `code/` if you want to. SilverStripe has adopted the PSR-4 approach and
have also started to use `src/` as a default folder location instead of
`code/`. If youre going to change, it's probably a good time to do it while you're
upgrading.
For examples, take a look at the file/folder structure compared to the
`composer.json` configuration in either the `framework` or `cms` modules.
Please note that there are changes to template structure which in some cases
require templates to be in a folder location that matches the class's namespace
that it belongs to, e.g. `themes/mytheme/templates/MyVendor/Foobar/Model/MyModel.ss`.
#### Get on board with PSR-# logging, too
One of the great changes that comes with SilverStripe 4 is the introduction of
[PSR-3](http://www.php-fig.org/psr/psr-3/) compatible logger interfaces. This
means we can use thirdparty services like Monolog.
Note that the old `SS_Log` class has been renamed to `SilverStripe\Logging\Log`,
but has also had most of its logic stripped out and the remainder is marked as
deprecated.
```ss
<!-- before -->
SS_Log::log('My error message', SS_Log::ERR);
<!-- after -->
Injector::inst()->get('Logger')->error('My error message');
```
If you call that multiple times in one class, you might want to add a getter
method to centralize it a little - but you probably should've had that already
in this case!
##### Unit tests and PSR-3 loggers
If you've got some code that you've tested originally using `SS_Log`, and now moved
to using a Monolog Logger then you may notice occasions where your unit tests pass
but output a bunch of warnings, debug information, etc. to `stderr`. This is because
Monolog will use `stderr` as the default Handler unless you specify one.
This isn't so much a regression as simply that you're now seeing things happening
in your code that didn't used to happen. You have a couple of options here. You can either:
* Address that there's possibly a logic problem in your unit tests
* Push a conveniently named `NullHandler` to monolog to quiet it.
```php
$logger = Injector::inst()->get('Logger');
$logger->pushHandler(new \Monolog\Handler\NullHandler);
```
It is not recommended to do this in your actual class. It's better to make use of
a convenient public getter method and configure this from the `setUp()` method of
your unit test class.
#### Upgrade module paths in file references
You should no longer rely on modules being placed in a deterministic folder (e.g. `/framework`),
@ -179,7 +412,19 @@ site _config.php files to use the `.env` configuration (below).
If you need to configure database details in PHP, use the new `DB::setConfig()` api instead.
You should remove any references to `ConfigureFromEnv.php` in your project, as this file
The global `$project` is deprecated in favour of the configuration setting
`SilverStripe\Core\Manifest\ModuleManifest.project`.
```ss
<!-- before -->
global $project;
$project = 'mysite';
<!-- after -->
SilverStripe\Core\Manifest\ModuleManifest:
project: mysite
```
Lastly, you should remove any references to `ConfigureFromEnv.php` in your project, as this file
is no longer necessary.
#### Upgrade of `_ss_environment.php` to `.env` configuration
@ -891,39 +1136,6 @@ these references should be replaced with `SQLSelect`. Legacy code which generate
`SQLQuery` can still communicate with new code that expects `SQLSelect` as it is a
subclass of `SQLSelect`, but the inverse is not true.
#### Upgrade code that references table names
A major change in 4.0.0 is that now tables and class names can differ from model to model. In order to
fix a table name, to prevent it being changed (for instance, when applying a namespace to a model)
the `table_name` config can be applied to any DataObject class.
```php
namespace SilverStripe\BannerManager;
use SilverStripe\ORM\DataObject;
class BannerImage extends DataObject
{
private static $table_name = 'BannerImage';
}
```
In order to ensure you are using the correct table for any class a new [DataObjectSchema](api:SilverStripe\ORM\DataObjectSchema) service
is available to manage these mappings (see [versioned documentation](/developer_guides/model/data_model_and_orm)).
```php
public function countDuplicates($model, $fieldToCheck)
{
$table = SilverStripe\ORM\DataObject::getSchema()->tableForField($model, $field);
$query = new SilverStripe\ORM\Queries\SQLSelect();
$query->setFrom("\"{$table}\"");
$query->setWhere(["\"{$table}\".\"{$field}\"" => $model->$fieldToCheck]);
return $query->count();
}
```
#### Upgrade BuildTask classes
Similarly to the `$table_name` configuration property for DataObjects, you should define a `private static $segment` for `BuildTask`