mirror of
https://github.com/silverstripe/silverstripe-framework
synced 2024-10-22 14:05:37 +02:00
First pass at upgrade docs
This commit is contained in:
parent
d7095c2213
commit
2b9369895d
@ -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 you’ve 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 don’t 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 you’re 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`
|
||||
|
Loading…
Reference in New Issue
Block a user