Upgrading an existing sprinkle from UserFrosting 4 to UserFrosting 5 can unfortunately be a difficult task. It all depends on how much customization of the core code you have done. Very basic sites will be easy to upgrade, very complex ones could be a nightmare. However, it's for the greater good; UserFrosting 5 is more modern and uses new techniques.
If you spot anything missing, don't hesitate to contribute to this page via the edit this page button at the top.
The upgrade path for your UserFrosting 4 sprinkle will depend on how many features you're using. The good news is, the database structure is the same, and the frontend is 90% the same.
To begin the upgrade journey, the first thing you should do is a fresh install of UserFrosting 5. This is important, as it will allow you to familiarize yourself with the new structure, as well as validate that your local development environment is up to date and meets the minimum requirements.
Once you have a functioning vanilla version of UserFrosting 5, you can begin to upgrade your sprinkle.
As seen on the previous page, one of the biggest changes is the app structure. It's recommended before you start to head over to Chapter 3 - App Structure, to learn more about this new structure.
Once you're familiar with the new structure, it's time to move things around so your sprinkle meets the new structure. There are two options here: You can either start from scratch from the Skeleton repo, or you can manually upgrade in place.
The first option is easier as the base has been set up for you, and you can start right away moving your code into the skeleton created from the sprinkle template, in a new git repository. However, its drawback is you'll probably lose your Git History. The second option is harder, but since you're starting from your existing code, you'll keep your git history if your code is saved on GitHub for example.
To start with this option, the first step is to create a fresh install from the app skeleton. You'll then have an empty sprinkle with the new structure, ready to copy your code into it. However, there are some steps you need to follow before going further.
composer.json
The Skeleton comes with a basic composer.json
. This defines the PSR-4 autoload namespace to UserFrosting\App\
. You should edit this file to fit your sprinkle, as well as use the same namespace as your old sprinkle.
You'll also need to update the namespace in every existing class, index.php
, and bakery
. See Customizing Your Sprinkle for more information.
Once this is done, you can run composer update
to fetch dependencies.
Next up, you should familiarize yourself with the Sprinkle Recipe. Right now, the only thing you must update is the sprinkle name, but we'll come back later to the recipe.
The last part is to move your code from app/sprinkles/{YourSprinkle}/
from your old install (usually from app/sprinkles/{YourSprinkle}/
) to app/
in the new directory.
At this point, you can skip to Upgrading components.
To start with this option, you should already be familiar with UserFrosting 5 directory structure, as it involves moving some directories around and editing some files. It also assumes your code (your sprinkle) was located (and not as a community sprinkle for example). You should have a UserFrosting 5 skeleton repo on hand to copy some files.
composer.json
bakery
build/
vagrant/
public/index.php
app/system/
app/tests/
app/defines.php
app/.htaccess
app/sprinkles/account/
app/sprinkles/admin/
app/sprinkles/core/
app/sprinkles.example.json
app/sprinkles.json
app/sprinkles/{YourSprinkle}/
to app/
, and delete the empty app/sprinkles/
directory./public/index.php
/bakery
/package.json
/webpack.config.js
/webpack.entries.js
docker-compose.yml
docker/
.gitignore
composer.json
In UserFrosting 4, your composer.json
was located in app/sprinkles/{YourSprinkle}/composer.json
. It was merged with the main composer file and the dependent sprinkles on build. With UserFrosting 5, there's only one composer.json
: Yours. And it lives in /composer.json
.
This step requires you to merge your composer.json
with UF5's. Start by moving your file, which should now be located at /app/sprinkles.json
to /composer.json
.
Next, you'll need to update some dependencies. Open composer.json
from the skeleton, and copy every dependency from required
and require-dev
from it to your composer.json
.
You should also update the path for the autoload
and autoload-dev
sections to point to app/src/
and app/tests/
respectively.
Once this is done, you can run composer update
to fetch dependencies.
The next step is to create your sprinkle recipe.
Start by:
app/src/MyApp.php
from the skeleton into your app, inside app/src/
MyApp
to whatever you want. Simply don't forget to adapt the next steps with the name you chose.app/src/MyApp.php
to the namespace you use in your composer.json
.We'll update the rest of your recipe later.
Finally, you'll need to update both entry files, aka /bakery
and /public/index.php
, with the correct reference to your recipe. Open both files, and replace UserFrosting\App\MyApp
and MyApp
with the correct reference to your recipe. See this page for more information and examples.
At this point, your UserFrosting 5 app is kind of ready to work. You simply need to upgrade every component you use. The following list might contain stuff you're not using, but you should still go through them as they contain links and tips you may need later.
Remember, this guide will give you only the big picture of what changed, but it will point you to the relevant parts of the documentation where more detail can be found.
It's important to note some changes have been applied at large and affect pretty much every PHP class, based on PHP 8 new features. These changes include:
Keep this in mind, especially if you've extended built-in classes. Not only may these classes have been renamed or moved, but the method declaration might have changed even if the code of these methods hasn't.
Services have been updated for UserFrosting 5. While the principle is the same, the way to register a service is different. Services are now served by the new dependency injection container, PHP-DI. You should head over to the Dependency Injection Chapter to learn more about PHP-DI integration in UserFrosting 5 before going further.
Your services definition must first be updated to implement UserFrosting\ServicesProvider\ServicesProviderInterface
. For example:
OLD:
class ServicesProvider
{
public function register(ContainerInterface $container)
{
// ...
}
}
NEW:
use UserFrosting\ServicesProvider\ServicesProviderInterface;
class ServicesProvider implements ServicesProviderInterface
{
public function register(): array
{
return [
// ...
];
}
}
You'll also need to register your service in your recipe. Check out Adding Services for more information.
Finally, instead of injecting the whole container and retrieving your service from it, you should inject the service directly into the class using autowiring in the class constructor or through route service injection for example.
For example:
OLD:
public function __construct($ci)
{
$this->camHelper = $ci->camHelper;
}
NEW:
public function __construct(protected CamHelper $camHelper): void
{
}
The classmapper has been removed in UF5. PHP-DI should be used instead, via the "autowire" and interface binding. Existing classmapper definitions should be moved inside a service, and calls to the classmapper should be updated to use dependency injection via the controller or other methods.
Migrations are mostly the same, only the class structure has changed, as well as the need to register migrations in your Sprinkle Recipe. The key points regarding migration are as follows:
Up/Down return type: The up()
and down()
methods must now have a return type of void
.
Migrations must now extend UserFrosting\Sprinkle\Core\Database\Migration
. Change use UserFrosting\System\Bakery\Migration;
to use UserFrosting\Sprinkle\Core\Database\Migration;
in every one of your migrations.
Dependencies must now be declared in a static property. Change public $dependencies = [];
to public static $dependencies = [];
in every one of your migrations.
Migrations are not auto-discovered anymore. You need to add them to your sprinkle recipe, using MigrationRecipe
. See the migration chapter for more information and a detailed guide.
Seeds are also mostly the same; they just need to implement \UserFrosting\Sprinkle\Core\Seeder\SeedInterface
and have a run()
function with a return type of void
. They are also not auto-discovered, so need to be added to your sprinkle recipe using SeedRecipe
.
See the seeding chapter for more details.
The only change in the database model is the $timestamps
property is now true
by default. It used to be false
. public $timestamps = true;
can be removed from your models unless you're not using timestamps, in which case you should add public $timestamps = false;
.
The way to register routes has changed. The definition is mostly the same; however, the routes are now real PHP classes instead of static PHP resources. Check out the Registering routes guide for more information.
To update your routes, you should start by:
app/routes/*
to app/src/Routes/*
.A few other key points to know:
::class
operator.authGuard
must be updated to UserFrosting\Sprinkle\Account\Authenticate\AuthGuard::class
.The Sprunje class used to accept options in the constructor. To make it easier to inject dependencies, options should now be defined using the setOptions
method. Sprunje should now be injected into controllers.
OLD:
public function camsList(Request $request, Response $response, array $args)
{
// GET parameters
$params = $request->getQueryParams();
/** @var /UserFrosting\Sprinkle\Core\Util\ClassMapper $classMapper */
$classMapper = $this->ci->classMapper;
/** @var \UserFrosting\Sprinkle\Core\Router $router */
$router = $this->ci->router;
$sprunje = new CamsSprunje($classMapper, $params, $router);
return $sprunje->toResponse($response);
}
NEW:
public function camsList(Request $request, Response $response, CamsSprunje $sprunje): Response
{
// GET parameters
$params = $request->getQueryParams();
return $sprunje->setOptions($params)->toResponse($response);
}
This also means the Classmapper is no longer available in Sprunjes. You should inject the necessary classes and services into your Sprunjes.
Simple changes have been made to controller classes:
extends SimpleController
, no extension is required anymore.use Slim\Http\Request;
must be changed to use Psr\Http\Message\ServerRequestInterface as Request;
use Slim\Http\Response;
must be changed to use Psr\Http\Message\ResponseInterface as Response;
view
service, inject Slim\Views\Twig
.$args
variables, should now be directly injected. See Retrieving URL Parameters for more information.See the Controller classes guide for more information.
SimpleController
, note that every controller class from the default sprinkles has been moved, renamed, and rewritten as Action classes. You will need to check out the sprinkle source code to find out how to update your sprinkle.Simple changes have been made to bakery commands:
Symfony\Component\Console\Command\Command
instead of UserFrosting\System\Bakery\BaseCommand
.use UserFrosting\Bakery\WithSymfonyStyle;
trait to access $this->io
.return self::SUCCESS;
or return self::FAILURE;
.The biggest change is you're now required to register your command in your sprinkle recipe. Check out the Bakery CLI chapter for more information.
Also note that the create-admin
command has been renamed create:admin-user
. If you were adding custom commands to the "bake" command, you can now use the Extending Aggregator Commands guide to achieve this more easily.
Not much has changed regarding the Resource Locator. Refer to the Locator Service page for more information. Note, however, that the two streams below have been renamed:
Three points are to be considered when working with templates:
First, sprinkles have been renamed. If you're extending a default sprinkle, you'll need to update the sprinkle reference in the extends
tag. For example: {% extends "@admin/pages/activities.html.twig" %}
=> {% extends "@admin-sprinkle/pages/activities.html.twig" %}
. Check the table below for a list of sprinkle identifiers.
Name | Slug |
---|---|
Admin Sprinkle | admin-sprinkle |
AdminLTE Theme | adminlte-theme |
Account Sprinkle | account-sprinkle |
Core Sprinkle | core-sprinkle |
In a similar way, some Twig templates have been moved to the "AdminLTE" sprinkle. Be sure to check the new structure if you're extending templates with the extends
tag. Some template files previously in the Admin Sprinkle might be in the AdminLTE sprinkle now.
FontAwesome has also been updated, and references to icons must also be updated: fa
-> fas
.
PathFor
has been changed. To generate a route based on its name, inject UserFrosting\Sprinkle\Core\Util\RouteParserInterface
and use the urlFor
method. use UserFrosting\Support\Exception\ForbiddenException;
=> use UserFrosting\Sprinkle\Account\Exceptions\ForbiddenException;
. Check out the Exception and Error Handling guide for more information.If your sprinkle was implementing a custom post-login destination, be sure to check out the updated recipe.
If your sprinkle had automated testing:
setupTestDatabase
has been removed, it's no longer necessary.UserFrosting\Sprinkle\Core\Tests\RefreshDatabase
is now UserFrosting\Sprinkle\Core\Testing\RefreshDatabase
.TestDatabase
is removed.withTestUser
usage has been updated.Asset management has been completely changed. Instead of a custom solution, UserFrosting 5 now uses Symfony's Webpack Encore to handle and build frontend assets. Your first stop should be the Asset Chapter or the documentation for an in-depth guide for this new system.
The key points here are:
asset-bundles.json
must be replaced with a new entrypoint and entries.content/scripts_site.html.twig
and content/stylesheets_site.html.twig
files from the skeleton repo for an example.