-
PHP 7.4
-
MySQL 5.7
- Note: We are using Percona 8.0 in production.
-
Nette 3.1
- Packages dependant on Nette were updated too (e.g.
latte/latte
,kdyby/translation
,contributte/forms-multiplier
). Checkcomposer.json
for current minimal versions.
- Packages dependant on Nette were updated too (e.g.
Check the official Nette guide for migrating to version 3.0. The following steps are changes we had to apply in our CRM extensions.
Package rector/rector
is the tool that helped us with the upgrade of all our CRM extensions. Check GitHub for more details.
This is the config we used for the upgrade itself.
<?php
declare(strict_types=1);
use Rector\Core\Configuration\Option;
use Rector\Core\ValueObject\PhpVersion;
use Rector\Nette\Set\NetteSetList;
use Symfony\Component\DependencyInjection\Loader\Configurator\ContainerConfigurator;
return static function (ContainerConfigurator $containerConfigurator): void {
$parameters = $containerConfigurator->parameters();
// paths to refactor
$parameters->set(Option::PATHS, [
// set this to path to your extension;
// no need to check CRM extensions
__DIR__ . '/extensions',
// updates nette packages automatically;
// check result against crm-application-module/composer.json
__DIR__ . '/composer.json',
]);
$parameters->set(Option::PHP_VERSION_FEATURES, PhpVersion::PHP_74);
// apply upgrade rules for Nette 3.0
$containerConfigurator->import(NetteSetList::NETTE_30);
};
-
Replace keyword
class
withfactory
when setting up factory service.gatewayFactory: - class: Crm\PaymentsModule\GatewayFactory + factory: Crm\PaymentsModule\GatewayFactory setup: - registerGateway(paypal, Crm\PaymentsModule\Gateways\Paypal)
-
Replace use of
on
/off
values withyes
/no
ortrue
/false
.translation: resolvers: - session: on - header: off + session: yes + header: no
-
Replace keyword
_extends
with_prevent_merging
when overriding setup of service.# override setup of HermesDriver for tests hermesDriver: factory: Crm\ApplicationModule\Hermes\DummyDriver setup: - _extends: true + _prevent_merging: true
Static Nette\DI\Compiler::loadDefinitions()
is deprecated in favor of non-static method Compiler::loadDefinitionsFromConfig()
(compiler is accessible through $this->compiler
).
Example of changes in our PaymentsModuleExtension
:
namespace Crm\PaymentsModule\DI;
use Kdyby\Translation\DI\ITranslationProvider;
use Nette\DI\CompilerExtension;
final class PaymentsModuleExtension extends CompilerExtension implements ITranslationProvider
{
private $defaults = [];
public function loadConfiguration()
{
- $builder = $this->getContainerBuilder();
// set default values if user didn't define them
$this->config = $this->validateConfig($this->defaults);
// load services from config and register them to Nette\DI Container
- Compiler::loadDefinitions(
- $builder,
+ $this->compiler->loadDefinitionsFromConfig(
$this->loadFromFile(__DIR__.'/../config/config.neon')['services']
);
}
-
Interface
Nette\Mail\IMailer::send()
method now returnsvoid
. No changes are required if you use our REMP Mailer. -
Inteface
Nette\Application\IResponse::send()
method now returnsvoid
. No changes required if you use our responses (eg.JsonResponse
,RedirectResponse
,XmlResponse
). -
Interface
Nette\Routing\IRouter
was renamed toNette\Routing\Router
. Return types were added. No changes are required if you don't implement your own router. -
Multiple
Nette\Database\Table
classes and interfaces now have return types. We had to fix classes that extend or implement them. Eg.Crm\ApplicationModule\ActiveRow
,Crm\ApplicationModule\DataRow
,Crm\ApplicationModule\Selection
). -
Misc renames & return types (Nette interfaces changed) // TODO
Quote from Nette migration guide:
Constructor of
Nette\ComponentModel\Component
has not been used for years and was removed in version 3.0. It's a BC break. If you call parent constructor in your component or presenter inheriting fromNette\Application\UI\Presenter
, you must remove it.
All CRM components were fixed. Eg. Crm\AdminModule\Components\AdminMenu
:
class AdminMenu extends UI\Control
public function __construct(User $user)
{
- parent::__construct();
$this->user = $user;
}
If you used an object with {plink}
or {link}
in Latte templates, switch to the object's ID. Latte link helpers now expect string.
- <li><a href="{link :Users:UsersAdmin:Show $current_user}"> //...
+ <li><a href="{link :Users:UsersAdmin:Show, $current_user->id}"> //..
The
Nette\Security\Passwords
class is now used as an object, ie the methods are no longer static.
If you use methods from Nette\Security\Passwords
, you need to inject (or require from DI) service Nette\Security\Passwords
and use it as the object. Eg.
class DemoClass
{
+ /** @var Nette\Security\Passwords */
+ private $passwords;
+
+ public function __construct(Nette\Security\Passwords $passwords)
+ {
+ $this->passwords = $passwords;
+ parent::__construct();
+ }
public function demoMethod($password)
{
- Nette\Security\Passwords::hash($password);
+ $this->passwords->hash($password);
}
}
Second parameter $whenBrowserIsClosed
of Nette\Security\User::setExpiration()
was deprecated. Set option Nette\Security\IUserStorage::CLEAR_IDENTITY
if you want to clear the identity after session expiration (see what it means in Nette docs).
public function formSucceeded($form, $values)
{
if ($values->remember) {
- $this->user->setExpiration('14 days', false);
+ $this->user->setExpiration('14 days');
} else {
- $this->user->setExpiration('20 minutes', true);
+ $this->user->setExpiration(
+ '20 minutes',
+ Nette\Security\IUserStorageIUserStorage::CLEAR_IDENTITY
+ );
}
Use Nette\Forms\Controls\BaseControl::setHtmlAttribute()
instead.
Copy netteForms.js
into www/layout
folders:
-
www/layouts/admin/js/
-
www/layouts/default/js/
Download netteForms.js
from link: https://nette.github.io/resources/js/3/netteForms.js
-
Class
Crm\ApiModule\Api\JsonResponse
doesn't extendNette\Application\Responses\JsonResponse
anymore. The parent method was changed tofinal
. We copied methods from it into our response (to fulfill interface). No changes are required. -
Extension
contributte/forms-multiplier
was updated. They renamed namespaceWebChemistry
toContributte
. If you use forms multiplier ($form->addMultiplier()
), you have to fix imports.
Check the official Nette guide for migrating to version 3.1. The following steps are changes we had to apply in our CRM extensions.
Package rector/rector
is the tool that helped us with the upgrade of all our CRM extensions. Check GitHub for more details.
This is the config we used for the upgrade to Nette 3.1.
<?php
declare(strict_types=1);
use Rector\Core\Configuration\Option;
use Rector\Core\ValueObject\PhpVersion;
use Rector\Nette\Set\NetteSetList;
use Symfony\Component\DependencyInjection\Loader\Configurator\ContainerConfigurator;
return static function (ContainerConfigurator $containerConfigurator): void {
$parameters = $containerConfigurator->parameters();
// paths to refactor
$parameters->set(Option::PATHS, [
// set this to path to your extension;
// no need to check CRM extensions
__DIR__ . '/extensions',
// updates nette packages automatically;
// check result against crm-application-module/composer.json
__DIR__ . '/composer.json',
]);
$parameters->set(Option::PHP_VERSION_FEATURES, PhpVersion::PHP_74);
// apply upgrade rules for Nette 3.1
$containerConfigurator->import(NetteSetList::NETTE_31);
};
Nette\Configurator
was moved to Nette\Bootstrap\Configurator
. It is used in ApplicationModule
's Core.php
to configure and create Nette's DI container. If you have own Core.php
alternative / implementation, you'll need to fixConfigurator
import.
Nette\Database\IRow
is deprecated; useNette\Database\Row
.Nette\Database\Table\IRow
is deprecated; useNette\Database\Table\ActiveRow
.
We switched everywhere to Nette\Database\Table\ActiveRow
. Using Nette\Database\Row
is not satisfactory for our needs. And also Nette\Database
changed few arguments to typed. So using IRow/Row is not possible in some cases. You'll have to switch to ActiveRow
too (in some cases; and you should in the rest places).
Crm\ApplicationModule\DataRow
was used as dummy wrapper for sending emails to email addresses without user entry. NotificationEvent
now requires ActiveRow
so DataRow
had to be replaced. In case you need to send NotificationEvent
to email without user, you can now use Crm\ApplicationModule\ActiveRowFactory
.
class ExampleClass
{
/** @var \League\Event\Emitter @inject */
public $emitter;
/** @var \Crm\ApplicationModule\ActiveRowFactory @inject */
public $activeRowFactory;
public function sendNotificationToExample()
{
$userRow = $this->activeRowFactory->create([
'email' => '[email protected]',
]);
$this->emitter->emit(new NotificationEvent($this->emitter, $userRow, 'example_template'));
}
}
Getting container directly from Presenters (all extending Nette\Application\UI\Presenter
) is now deprecated in Nette 3 in favor of using DI. Since some parts of the CRM still require the DI container to be available in presenter, we've overriden BasePresenter::getContext()
and made BasePresenter::$container
available.
If your presenters extend Crm\ApplicationModule\Presenters\BasePresenter
, no change is necessary. If your presenters don't extend it and need DI container, you'll have to inject it manually.
Notes:
- Consider using proper DI instead of loading service manually from container.
- Not extending
Crm\ApplicationModule\Presenters\BasePresenter
or not injecting DI container to your presenters might cause deprecation notices in widgets rendering other widgets.
Multiple Nette interfaces lost I prefix. Follow migration guide mentioned above. Here are interfaces we had to fix in extensions:
Nette\Application\IResponse
is deprecated; useNette\Application\Response
.Nette\Application\UI\ITemplate
is deprecated; useNette\Application\UI\Template
.Nette\Caching\IStorage
is deprecated; useNette\Caching\Storage
.Nette\Mail\IMailer
is deprecated; useNette\Mail\Mailer
.Nette\Security\IAuthorizator
is deprecated; useNette\Security\Authorizator
.Nette\Security\Identity
is deprecated; useNette\Security\SimpleIdentity
.Nette\Localization\ITranslator
is deprecated; useNette\Localization\Translator
.
- Changed deprecated
{ifCurrent 'link'}
latte tag to{isLinkCurrent('link')}
latte function. (To be consistent, we changed also{$presenter->isLinkCurrent('link')}
to new{isLinkCurrent('link')}
). - Fixed deprecated use of vars without dollar sign.
{var myVariable = ...}
changed to{var $myVariable = ...}
.
- We switched from
$form->values['field_name]
to$form->getValues()['field_name]
(recommended by rector). - Check validation methods of forms (when used with
$form->onValidate[]
). It's possible that$form->values
(or$form->getValues()
) won't return all values for validation. Use$form->getUnsafeValues()
instead.