Due to overwhelming support from the community, Winter CMS is updating its foundation framework to the latest Long Term Support (LTS) release. As a result, there are some new requirements to run Winter and some code changes required.
From the proposed Build 1.2.0 your webserver will require PHP 8.0.2 or above to use Winter CMS. After this date, websites using PHP 7.0-7.2.8 will still function normally but will no longer be able to receive updates or install the latest version.
There are various code changes that may be required, including code found in plugins and themes, both private and public depending on what features you are utilizing.
- Build 1.2.0 is available as a test update from 4 May 2021. Stable release date to be announced.
- PHP: 8.0.2
- MariaDB 10.2+ (Version Policy)
- MySQL 5.7+ (Version Policy)
- PostgreSQL 9.6+ (Version Policy)
- SQLite 3.8.8+
- SQL Server 2017+ (Version Policy)
- 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
NOTE: The PHP 7.4 branch, and those before it, are now unsupported.
- Change the following composer.json requirements:
"require": {
"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"
},
"require-dev": {
"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"
},- If you have the following lines in your
composer.jsonfile, please remove these:
"autoload-dev": {
"classmap": [
"tests/concerns/InteractsWithAuthentication.php",
"tests/fixtures/backend/models/UserFixture.php",
"tests/TestCase.php",
"tests/PluginTestCase.php"
]
},- You may also delete the
testsfolder completely, as these testing files now reside in the modules, unless you have your own tests within this folder. - Run
composer update. - If
config/app.phpmakes reference toIlluminate\Http\Request::HEADER_X_FORWARDED_ALL, change it to'HEADER_X_FORWARDED_ALL'
Unexpected token "name" of value "if" ("end of statement block" expected).:- See https://twig.symfony.com/doc/2.x/deprecated.html#tags
- Use the
| filterfilter or a conditional check inside of the loop block if the variable is affected by the contents of the loop. - This is most likely to affect users of the Winter.Pages plugin, simply update
{% for item in items if not item.viewBag.isHidden %}to{% for item in items | filter(item => not item.viewBag.isHidden) %}in your custom partials.
- The
str_contains()helper provided by Laravel has a slight signature mismatch compared to the one provided by the PHP 8.0 internals.
Any required code changes are described below in sections based on related functionality that you may or may not be using. If you are using the described functionality, please review the section and make the required changes.
Only potentially breaking changes are called out in this document, for the full list of all changes, please see the 1.2.0 release note.
If you are using any of the following functionality it's highly recommended that you take a look at the relevant section in this guide and make any required changes to your usage:
- Twig
- Configuration files (
/config/*.php) - Emails
- Storage & Files
- General Cleanup
- Facades
- Any packages made for Laravel
- Unit Testing
- Storm Library Internals
- Upgrade Guides
$twigEnvironment->loadTemplate($name)now requires$clsas the first parameter. Switch to$twigEnvironment->load($name);instead. See https://github.com/twigphp/Twig/commit/653dddd1f962e5cf6818f11e8757c82becd35a4f{% filter %}tag has been removed from Twig v3.0 (backported but use{% apply %}instead going forward){% spaceless %}tag has been removed from Twig v3.0 (backported but use{% apply spaceless %){% endapply %}instead going forward)
Review the changes to the default configuration files and implement any changes as desired; the following items are called out as potentially having an impact:
config/app.php:- An application key is no longer provided by default, if your application does not yet have one set, run
artisan key:generate. Illuminate\Http\Request::HTTP_X_FORWARDED_ALLhas been removed in Symfony 6, but it's referenced with no intermediate layer in the default app.php config file from v1.1.4 to v1.1.8. See https://github.com/wintercms/storm/commit/fcecefda3fd3966310306b5799852c53d6330a64 for more details.
- An application key is no longer provided by default, if your application does not yet have one set, run
config/database.php:- Removed support for
database.useConfigForTesting, useconfig/testing/database.phpto override testing defaults instead. - Setting a
varcharmaxonmysqldatabase connections is no longer supported as the minimum required version of MySQL now supports 255 character UTF8 strings by default.
- Removed support for
config/mail.php:- The structure has changed, update your local copy to match the one now provided on the 1.2 branch. The old one should continue working but it is recommended to update it to reflect the new structure.
config/filesystems.php:- The
localdisk currently needs avisibility => 'public'setting in order for the files/folders under/storage/app/resizedto be publicly accessible when using the image resizer.
- The
- 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, several methods and return types have changed.
- 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$diskinstances if desired.
The translator.beforeResolve event has been removed for performance reasons. Lang::set($key, $value, $locale) can be used as a replacement.
Winter < v1.2
Event::listen('translator.beforeResolve', function ($key, $replaces, $locale) {
if ($key === 'validation.reserved') {
return Lang::get('winter.builder::lang.validation.reserved');
}
});Winter >= v1.2
Lang::set('validation.reserved', Lang::get('winter.builder::lang.validation.reserved'));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');server.php:- It is no longer required for the
artisan servecommand to function if you haven't modified it from the default; it can be removed.
- It is no longer required for the
- Facades must return string keys rather than objects (See laravel/framework#38017)
Winter\Storm\Support\Facades\Strfacade has been removed, useWinter\Storm\Support\Strdirectly instead.
The version of Laravel has been changed from 6.x LTS to 9.x LTS. 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.
If you are running unit testing for Winter CMS development, you will need to make some changes to your composer.json file and remove the tests folder from your installation to get the updates to the unit tests.
This block of code is no longer required in your composer.json file:
"autoload-dev": {
"classmap": [
"tests/concerns/InteractsWithAuthentication.php",
"tests/fixtures/backend/models/UserFixture.php",
"tests/TestCase.php",
"tests/PluginTestCase.php"
]
},Since the testing files now reside within the modules folder, you may need to update your phpunit.xml configuration files and test cases if they make reference to any files in their old locations. To help ease the transition, you may use the php artisan winter:test -p <your plugin code> command, which will use the correct bootstrap file for Winter 1.2 testing. You may keep the old bootstrap configuration in your phpunit.xml file if you wish to test both Winter 1.1 and 1.2.
Since the base PluginTestCase class has also been moved, any test case files that are extending this class will need to either update the reference to \System\Tests\Bootstrap\PluginTestCase, or alternatively, you can use the following code to support testing on both Winter 1.1 and 1.2:
// 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 BaseTestCaseVersion 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
- To prevent unsafe model instantiating, the model constructors are now forced to only allow a single
$attributesparameter via an interface (\Winter\Storm\Database\ModelInterfaceand\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
$attributesparameter 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
MorphToManyclass now extends theMorphToManyclass from Laravel, as opposed to theBelongsToManyclass in Winter. This prevents repeated code in the WinterMorphToManyclass and maintains covariance with Laravel. This will mean that it will no longer inherit from the WinterBelongsToManyclass. To allow for this, we have converted most of the overriddenBelongsToManyfunctionality in Winter into a trait (Concerns\BelongsOrMorphsToMany). TheBelongsToManyrelation class now also uses this trait. - The relation traits found in
src/Database/Relationshave been moved tosrc/Database/Relations/Concerns, in order to keep just the actual relation classes within thesrc/Database/Relationsdirectory. In the unlikely event that you are using a relation trait directly, please rename the trait classes to the following:Winter\Storm\Database\Relations\AttachOneOrManytoWinter\Storm\Database\Relations\Concerns\AttachOneOrManyWinter\Storm\Database\Relations\DeferOneOrManytoWinter\Storm\Database\Relations\Concerns\DeferOneOrManyWinter\Storm\Database\Relations\DefinedConstraintstoWinter\Storm\Database\Relations\Concerns\DefinedConstraintsWinter\Storm\Database\Relations\HasOneOrManytoWinter\Storm\Database\Relations\Concerns\HasOneOrManyWinter\Storm\Database\Relations\MorphOneOrManytoWinter\Storm\Database\Relations\Concerns\MorphOneOrMany
- 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.
- The
Filesystem::symbolizePathmethod's$defaultparameter now accepts astring,boolornull. Only in the case ofnullwill the method return the original path - the given$defaultwill 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::isPathSymbolmethod previously returned the path symbol used, as a string, if one was found andfalseif 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 -trueif a path symbol is used, otherwisefalse. - Many classes within the
Filesystemnamespace 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.
- The
Winter\Storm\Foundation\Applicationclass callback methodsbeforeandafterwere documented asvoidmethods, but returned a value. These no longer return a value.
- To prevent unsafe model instantiating, the model constructors are now forced to only allow a single
$attributesparameter via an interface (\Winter\Storm\Database\ModelInterfaceand\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
insertmethod now returns anintrepresenting the created model's filesize, not abool. - The Halcyon Builder
insertmethod requires the$valuesparameter 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).
- The
Winter\Storm\Html\FormBuilderclass 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.
- The
Bracketclass constructor is nowfinalto prevent unsafe static calls to theparsestatic method. - The
Bracket::parseString()method previously returnedfalseif 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.beforeParseevent in theMarkdownclass sent a singleMarkdownDatainstance as a parameter to the listeners. It now sends an array with theMarkdownDatainstance as the only value, to meet the signature requirements for events. - The
Syntax\FieldParserclass constructor has been madefinalto prevent unsafe static calls to theparsestatuc method. - The
$templateparameter for theSyntax\FieldParserclass 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\Parserclass constructor has been madefinalto prevent unsafe static calss to theparsestatic method. - The
$templateparameter for theSyntax\Parserclass 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
Winter\Storm\Support\Testing\Fakes\MailFake::queue()method has had its signature re-arranged to remain compatible with Laravel'sMailFakeclass, with the$queueparameter being moved to the second parameter. The new signature is($view, $queue, $data, $callback).