Upgrade Guide (v1.1 to v1.2)
With Winter's core goal of stability, upgrading your Winter CMS v1.1 site to the new v1.2 branch should be relatively straight-forward. However, as with all major releases, there may be some breaking changes or new requirements that may mean some adjustments to your projects.
We make every effort to document all new requirements and breaking changes, however, your project may have some very unique edge cases that we have not accounted for. If your project does not work after following the guide below, please feel free to submit an issue on Github or reach out to the community on Discord for assistance.
IMPORTANT: If your site runs a version of Winter CMS v1.0, please upgrade to v1.1 first before going through this upgrade guide.
New requirements
Application server
- PHP 8.0.2 is now the minimum supported version. PHP 7.4 and below is now unsupported.
Database server
- The following versions of the database servers supported by Winter CMS are now the minimum versions required:
- MySQL 5.7+ (Version Policy)
- MariaDB 10.2+ (Version Policy)
- PostgreSQL 9.6+ (Version Policy)
- SQLite 3.8.8+
- SQL Server 2017+ (Version Policy)
Dependencies
- The following dependencies are now used in Winter CMS 1.2. These will automatically be installed when upgrading.
- Laravel: 9.x
- Laravel Tinker: 2.7
- Twig: 3.x
- Symfony\Yaml: 5.1
- PHPUnit: 9.5.8
- Mockery: 1.4.4
- Assetic: 3.0
Composer updates
Impacts: All users.
If you installed your project via Composer, you must make the following changes to the composer.json
file in the root directory of your project.
Within the require
section:
"php": "^8.0.2",
"winter/storm": "~1.2.0",
"winter/wn-system-module": "~1.2.0",
"winter/wn-backend-module": "~1.2.0",
"winter/wn-cms-module": "~1.2.0",
"laravel/framework": "^9.1",
"wikimedia/composer-merge-plugin": "~2.0.1"
Within the require-dev
section:
"phpunit/phpunit": "^9.5.8",
"mockery/mockery": "^1.4.4",
"fakerphp/faker": "^1.9.2",
"squizlabs/php_codesniffer": "^3.2",
"php-parallel-lint/php-parallel-lint": "^1.0",
"dms/phpunit-arraysubset-asserts": "^0.1.0|^0.2.1"
You must also remove the entire autoload-dev
section below, unless you are using this section for your own requirements.
"autoload-dev": {
"classmap": [
"tests/concerns/InteractsWithAuthentication.php",
"tests/fixtures/backend/models/UserFixture.php",
"tests/TestCase.php",
"tests/PluginTestCase.php"
]
},
Once done, run composer update
to install all the required dependencies and upgrade Winter CMS to version 1.2.
Tests folder
Impacts: All users.
The tests
folder in the root folder of your project is no longer required, as all Winter CMS tests are now stored in the modules that those tests relate to. You may remove the entire folder, unless you are using the folder to store your own application tests.
Server script
Impacts: All users.
The server.php
file located in your project root folder is no longer required for php artisan serve
to function. You may remove this if you wish, however, there is no harm to your project if you leave it there.
Configuration file changes
Impacts: Most users.
There have been signifcant changes to the default configuration files, mainly in those that are based on the Laravel framework's configuration files. You should review the changes to the default configuration files and implement any changes as desired.
The following items have the highest likelihood of having an impact on your projects:
config/app.php
- An application key is no longer provided by default. If your application does not yet have one set, run
php artisan key:generate
in your project root folder. -
Illuminate\Http\Request::HTTP_X_FORWARDED_ALL
has been removed in Symfony 6, but it's referenced with no intermediate layer in the defaultapp.php
config file for thetestedProxyHeaders
configuration from v1.1.4 to v1.1.8. See https://github.com/wintercms/storm/commit/fcecefda3fd3966310306b5799852c53d6330a64 for more details. If you are using this value fortrustedProxyHeaders
, change this to the stringHEADER_X_FORWARDED_ALL
.
config/database.php
- The
database.useConfigForTesting
configuration is no longer supported. Useconfig/testing/database.php
to override testing defaults instead. - Setting a
varcharmax
onmysql
database connections is no longer supported as the minimum required version of MySQL now supports 255 character UTF8 strings by default.
config/mail.php
- The structure has changed - update your local copy to match the one now provided on the 1.2 branch. The old structure may work, but it has been reported in some cases that it does not, so it is recommended to update it to reflect the new structure.
config/filesystems.php
- The
local
disk currently needs avisibility => 'public'
setting in order for the files and folders under/storage/app/resized
to be publicly accessible when using the image resizer.
Third-party email delivery providers
Impacts: Users of third-party email providers, plugin developers.
- Built-in support for SES, Postmark, Mailgun, Mandrill, SendGrid, & SparkPost mail drivers has been removed. Use the applicable first-party driver plugins as needed:
- Review the SymfonyMailer upgrade guide if you interact with mail message objects directly, as several methods and return types have changed.
Storage & files
Impacts: Rackspace storage users, plugin developers.
- The Rackspace Flysystem driver / adapter is no longer supported.
-
Symfony\Component\HttpFoundation\File\UploadedFile->getClientSize()
has been removed. UsegetSize()
instead. - The
getAdapter()
method on Storage disks is no longer present.getPathPrefix()
&setPathPrefix()
methods have been added to the$disk
instances if desired.
Localization changes
Impacts: Plugin developers.
The translator.beforeResolve
event has been removed for performance reasons. Lang::set($key, $value, $locale)
can be used as a replacement.
Overriding a specific key
Before Winter v1.2:
Event::listen('translator.beforeResolve', function ($key, $replaces, $locale) {
if ($key === 'validation.reserved') {
return Lang::get('winter.builder::lang.validation.reserved');
}
});
From Winter v1.2:
Lang::set('validation.reserved', Lang::get('winter.builder::lang.validation.reserved'));
Overriding an entire namespace
If you were using the event to extend / override an entire namespaced key (for example in order to share localization overrides that would normally be present in a project's lang
override folder at the project root between multiple projects via a plugin), then you could switch your code to use the following example:
Lang::set('winter.builder::lang', require __DIR__ . '/lang/en-ca/lang.php', 'en-ca');
Facades
Impacts: Plugin developers.
- Facades must return string keys rather than objects (See https://github.com/laravel/framework/pull/38017).
-
Winter\Storm\Support\Facades\Str
facade has been removed. UseWinter\Storm\Support\Str
directly instead. TheStr
alias now points toWinter\Storm\Support\Str
instead.
Laravel packages
Impacts: Plugin developers.
The version of Laravel has been changed from 6.x LTS to 9.x. If you are using packages made for Laravel, you may have to go through and update them to a version compatible with Laravel 9.x.
Unit testing
Impacts: Plugin developers that use test cases.
Unit testing should now be conducted using the php artisan winter:test
command, as opposed to running unit tests directly on phpunit
. This ensures that the correct bootstrap is used, as well as the necessary environment configuration is created.
If you have unit tests that extend either the base TestCase
or PluginTestCase
classes, these must now extend \System\Tests\Bootstrap\TestCase
and \System\Tests\Bootstrap\PluginTestCase
instead, respectively.
If your plugin is intended to work (and test) on both Winter 1.1 and 1.2, you may create a stub class in your test cases that will use the corresponding base test case class depending on the Winter CMS version in use.
// Create a stub BaseTestCase that extends the correct plugin test case file depending on Winter version
if (class_exists('System\Tests\Bootstrap\PluginTestCase')) {
class BaseTestCase extends \System\Tests\Bootstrap\PluginTestCase
{
}
} else {
class BaseTestCase extends \PluginTestCase
{
}
}
class MyTestCase extends BaseTestCase
Storm library internals
Impacts: Some users and plugin developers.
Version 1.2 of Winter includes a large code refactoring and documentation cleanup for the Storm library, to ensure that our base functionality is fully documented and works in a consistent and expected way. In addition, this brings our Storm library closer to the base Laravel functionality, which should make upgrades quicker and less painful in the future.
While we have ensured that the potential for breaking changes is low, there may be some cases of breaking functionality if the functionality used an undocumented or incorrectly-documented API. We will list all the changes below, grouped by the "package" within the Storm library:
- \Winter\Storm\Database
- \Winter\Storm\Extension
- \Winter\Storm\Filesystem
- \Winter\Storm\Foundation
- \Winter\Storm\Halcyon
- \Winter\Storm\Html
- \Winter\Storm\Parse
- \Winter\Storm\Support\Testing
Database
- To prevent unsafe model instantiating, the model constructors are now forced to only allow a single
$attributes
parameter via an interface (\Winter\Storm\Database\ModelInterface
and\Winter\Storm\Halcyon\ModelInterface
). This will ensure that calls likeModel::make()
orModel::create()
will execute correctly. It is possible that some people might have used additional parameters for their model constructors - these will no longer work and must be moved to another method. - Due to the above, Pivot model construction has been rewritten. The constructor used to allow 4 parameters but now only allows the one
$attributes
parameter as per the Model class. Construction now happens more closely to Laravel's format of calling aPivot::fromAttributes()
static method. If you previously usednew Pivot()
to create a pivot model, switch to usingPivot::fromAttributes()
instead. - The
MorphToMany
class now extends theMorphToMany
class from Laravel, as opposed to theBelongsToMany
class in Winter. This prevents repeated code in the WinterMorphToMany
class and maintains covariance with Laravel. This will mean that it will no longer inherit from the WinterBelongsToMany
class. To allow for this, we have converted most of the overriddenBelongsToMany
functionality in Winter into a trait (Concerns\BelongsOrMorphsToMany
). TheBelongsToMany
relation class now also uses this trait. - The relation traits found in
src/Database/Relations
have been moved tosrc/Database/Relations/Concerns
, in order to keep just the actual relation classes within thesrc/Database/Relations
directory. In the unlikely event that you are using a relation trait directly, please rename the trait classes to the following:-
Winter\Storm\Database\Relations\AttachOneOrMany
toWinter\Storm\Database\Relations\Concerns\AttachOneOrMany
-
Winter\Storm\Database\Relations\DeferOneOrMany
toWinter\Storm\Database\Relations\Concerns\DeferOneOrMany
-
Winter\Storm\Database\Relations\DefinedConstraints
toWinter\Storm\Database\Relations\Concerns\DefinedConstraints
-
Winter\Storm\Database\Relations\HasOneOrMany
toWinter\Storm\Database\Relations\Concerns\HasOneOrMany
-
Winter\Storm\Database\Relations\MorphOneOrMany
toWinter\Storm\Database\Relations\Concerns\MorphOneOrMany
-
Extension
- Previously, the
Winter\Storm\Extension\Extendable::extendClassWith()
method returned the current class if the extension name provided was an empty string. This appears to be a code smell, so this has been changed to throw an Exception.
Filesystem
- The
Filesystem::symbolizePath
method's$default
parameter now accepts astring
,bool
ornull
. Only in the case ofnull
will the method return the original path - the given$default
will be used in all other cases. This is the same as the original functionality, but we're documenting it in case you have customised this method in some fashion. - The
Filesystem::isPathSymbol
method previously returned the path symbol used, as a string, if one was found andfalse
if not found. However, the docblock stipulated, as well as the method name itself implied, that this is a boolean check function, so we have converted this to a straight boolean response -true
if a path symbol is used, otherwisefalse
. - Many classes within the
Filesystem
namespace have had type hinting and return types added to enforce functionality and clarify documentation. If you extend any of these classes in your plugins, you may need to update your method signatures.
Foundation
- The
Winter\Storm\Foundation\Application
class callback methodsbefore
andafter
were documented asvoid
methods, but returned a value. These no longer return a value.
Halcyon
- To prevent unsafe model instantiating, the model constructors are now forced to only allow a single
$attributes
parameter via an interface (\Winter\Storm\Database\ModelInterface
and\Winter\Storm\Halcyon\ModelInterface
). This will ensure that calls likeModel::make()
orModel::create()
will execute correctly. It is possible that some people might have used additional parameters for their model constructors - these will no longer work and must be moved to another method. - The Halcyon Builder
insert
method now returns anint
representing the created model's filesize, not abool
. - The Halcyon Builder
insert
method requires the$values
parameter to actually contain variables and will throw an Exception if an empty array is provided. Previously, this was silently discarded and returnedtrue
(although this would not actually save the file).
HTML
- The
Winter\Storm\Html\FormBuilder
class has had type hinting and return types added to enforce functionality and clarify documentation. If you extend this class in your plugin, you may need to make changes to your method signatures if you overwrite the base functionality.
Parse
- The
Bracket
class constructor is nowfinal
to prevent unsafe static calls to theparse
static method. - The
Bracket::parseString()
method previously returnedfalse
if a string was not provided for parsing, or the string was empty after trimming. Since the signature calls for a string, we won't check for this anymore. If the string is empty, an empty string will be returned. - The
markdown.beforeParse
event in theMarkdown
class sent a singleMarkdownData
instance as a parameter to the listeners. It now sends an array with theMarkdownData
instance as the only value, to meet the signature requirements for events. - The
Syntax\FieldParser
class constructor has been madefinal
to prevent unsafe static calls to theparse
statuc method. - The
$template
parameter for theSyntax\FieldParser
class constructor was originally optional. Since there is no purpose for this, and no way to populate the template after the fact, this has been made required. - The
Syntax\Parser
class constructor has been madefinal
to prevent unsafe static calss to theparse
static method. - The
$template
parameter for theSyntax\Parser
class constructor was originally optional. Since there is no purpose for this, and no way to populate the template after the fact, this has been made required.
Support\Testing
- The
Winter\Storm\Support\Testing\Fakes\MailFake::queue()
method has had its signature re-arranged to remain compatible with Laravel'sMailFake
class, with the$queue
parameter being moved to the second parameter. The new signature is($view, $queue, $data, $callback)
.
Upgrade guides for dependencies
Impacts: Informational only.