Search by

dresscode / upgrade-nette

david@grudl.com

👔 DressCode Upgrade for Nette: rewrites code written for older Nette, Latte and Tracy to the current API, annotations included, and reports the rest with what to write instead.

Package info

github.com/dg/dresscode-upgrade-nette

Homepage

Type:dresscode-plugin

pkg:composer/dresscode/upgrade-nette

Statistics

Installs: 6

Dependents: 0

Suggesters: 0

Stars: 0

Open Issues: 0

dev-master / 1.0.x-dev 2026-10-22 00:23 UTC

This package is auto-updated.

Last update: 2026-10-22 00:29:38 UTC


README

Latest Stable Version License

 

✅ Upgrades code for every Nette library, from 3.0 to today
✅ Knows what each variable is, so it rewrites only the right calls
✅ Reports what needs a human, with what to write instead
✅ From the author of Nette, written from every commit of its libraries

 

Upgrade a Nette application without hunting for renames. Install this package, run dresscode upgrade, and code written for older versions of Nette is rewritten to the API of the versions your project stands on:

- /** @persistent */
+ #[Persistent]

- private Context $database,
+ private Explorer $database,

- $page = $this->getParameter('page', 1);
+ $page = $this->getParameter('page') ?? 1;

- $this->invalidateControl('list');
+ $this->redrawControl('list');

- $form->addUpload('photos', 'Photos', true);
+ $form->addMultiUpload('photos', 'Photos');

- Json::encode($values, Json::PRETTY)
+ Json::encode($values, pretty: true)

Six changes from four libraries, the imports rewritten along with them, and not a byte more of the file touched. The package holds the data, what each version of Nette renamed, moved or retired; the rewriting is done by DressCode, the PHP coding standard and upgrade tool, which comes with it.

 

Installation and first run

1️⃣ Install it: composer require --dev dresscode/upgrade-nette
2️⃣ Upgrade the code: vendor/bin/dresscode upgrade
3️⃣ Read the diff, run your tests and PHPStan, and commit

The package brings DressCode along, and dresscode upgrade takes it as it finds it, with no configuration. Most of the rewrites need to know what a variable is, which DressCode asks your PHPStan, so the project needs phpstan/phpstan installed. The style of the code stays as it is: with a dresscode.neon, the upgrade keeps of its coding standard what the code already follows, and without one it changes nothing but the old API. Where it rewrote something, run it again, as the new code may hold more to upgrade.

To have every dresscode check and dresscode fix watch for the old API too, in CI or in a Git hook, turn the upgrade on in dresscode.neon; the upgrade is the set deprecations, with the types of the code:

typeAnalysis: phpstan

use:
	- upgrade-nette
	- deprecations

 

What gets upgraded

None of it is search and replace. DressCode asks PHPStan what each variable is, so getName() is rewritten where it is called on a FileUpload and nowhere else, and $this is known to be a presenter even in a method inherited from a parent. What the package rewrites:

  • renamed classes and interfaces: Nette\Configurator to Nette\Bootstrap\Configurator, IRouter to Nette\Routing\Router, IControl to Nette\Forms\Control, with the import, the type, new, instanceof and attributes,
  • constants out of upper case: Form::FILLED to Form::Filled, IResponse::S404_NOT_FOUND to IResponse::S404_NotFound, Cache::EXPIRE to Cache::Expire, chains across several versions included,
  • renamed methods: invalidateControl() to redrawControl(), getUnsafeValues() to getUntrustedValues(), Strings::contains() to str_contains(),
  • renamed parameters of calls with named arguments: setExpiration(time: ...) to setExpiration(expire: ...), also in the parent::__construct() of a child,
  • a default moved behind ??: getParameter('page', 1) to getParameter('page') ?? 1, the same with getQuery(), getPost(), getCookie(), getHeader() and getOption(),
  • magic properties to getters and setters: $form->action, $control->caption, $section->user, $section['user'],
  • flags to named arguments: Json::encode($value, Json::PRETTY), Strings::match() and its kin with PREG_* constants, Neon::encode() with Neon::BLOCK, the router with Router::ONE_WAY,
  • calls of another shape: addUpload($name, $label, true) to addMultiUpload(), getValues(true) to getValues('array'), Callback::closure() to Closure::fromCallable(),
  • annotations to attributes: @persistent and @crossOrigin in presenters, @filter and @function in the classes of Latte template parameters,
  • component hooks attached() and detached() to the callbacks of monitor() in the constructor, and the query string and the fragment of a link destination, link('Product:show?id=1#reviews'), to its arguments.

The rewritten code takes the shape of the file around it, or of your coding standard, if the configuration names one.

 

What is left to you

Where there is no replacement, or one that needs a decision, DressCode does not guess. It reports the place and says what to write instead:

Constant `Nette\Application\IRouter::SECURED` is forbidden: write the protocol, `https://`, into the mask of the route
Method `Nette\Http\UrlScript::setPath()` is forbidden: the class is immutable; take a changed copy with `withPath()`

An upgrade is a rewrite plus a list of what remains, and the list is half of its value. Every such sentence is written as an instruction, so the list can be worked through by you or handed to an AI coding agent as it is.

A few rewrites could change what the code does, such as a property read on the left of ??, where PHP first asks whether the property is set. Those wait for your consent: dresscode upgrade --ask-risky asks about each one with its diff, --fix-risky makes them all.

 

One major version at a time

The data of each library apply only when your project has it, and only the sections of the versions it stands on: the lowest version the constraint in composer.json allows. So an upgrade goes the way you would do it by hand: raise the constraint to the next major version, composer update, dresscode upgrade, tests, commit, and on to the next one. In each step the data meet the installed library, whose @deprecated annotations tell DressCode what the next version will remove.

Code can also be upgraded before the library is, with the key targets, which names the version to write for:

targets:
	nette/application: '3.2'
	nette/forms: '3.2'

dresscode config shows for every library the version the data start from and the versions a further update would lead to. An application written for Nette 2.4 is upgraded the same way, starting with 3.0.

 

Where the data come from

The data come from the author of Nette. Every library first got an upgrading guide, docs/upgrading.md in its repository, written from its whole history: thousands of commits read one by one, and the public API of each release compared with the one before. Every entry was then checked against the code of the release that made the change, because the tag decides, not anyone's memory.

The data are also checked against the installed libraries, so a replacement that does not exist cannot get in, and each library has a sample of old code that the data must turn into the expected new code. And they are kept where Nette is made, by the same hands that change the libraries.

Each entry is a line of text, even one that changes the shape of a call:

since 3.1:
	replacedClasses:
		Nette\Database\Context: Nette\Database\Explorer
	replacedMembers:
		'Nette\Http\FileUpload::getName()': getUntrustedName
	replacedCalls:
		'Nette\Database\Explorer::queryArgs($sql, $params)': 'query($sql, ...$params)'

 

Nette libraries and versions covered

All of them, with more than 900 entries, most libraries from their version 3.0 to the current one: nette/application, nette/assets, nette/bootstrap, nette/caching, nette/command-line, nette/component-model, nette/database, nette/di, nette/forms, nette/http, nette/mail, nette/neon, nette/php-generator, nette/robot-loader, nette/routing, nette/schema, nette/security, nette/tester, nette/utils, latte/latte and tracy/tracy. The manual lists the versions of each.

 

Limits

  • Most rewrites need PHPStan. dresscode upgrade does not run without it, and check and fix without typeAnalysis: phpstan rewrite only classes, functions and annotations.
  • DressCode runs on PHP 8.4 to 8.6. The code it upgrades may be written for PHP 8.0 and newer, but the package is installed into the project, so the project has to install on PHP 8.4 or newer.
  • The data fix the code, not its meaning. A change of behavior, the configuration in NEON and the syntax of Latte templates are not in the data; the upgrading guides of the libraries describe them. Run your tests after a fix.

 

Other ecosystems

package upgrades
dresscode/upgrade-nette every Nette library, most from 3.0
dresscode/upgrade-symfony the components and bridges of Symfony, from 6.0
dresscode/upgrade-laravel the Laravel framework from 6, and the attributes of Laravel 13
dresscode/upgrade-deegee Dibi and Texy

A package like these can be written for any library; the manual says how.

 

Development

The libraries the data are about are in require-dev, so the data are checked against their installed versions:

  • php tests/check.php <library> lints upgrading/<library>.neon and runs its sample, tests/samples/<library>.code, comparing the result with .expected and .violations,
  • php tests/check.php <library> --update writes those two from the run; read the diff, it is what the data do,
  • vendor/bin/tester tests runs all of it.