Upgrade to Nextcloud 20
Note
Critical changes were collected on GitHub. See the original ticket for links to the pull requests and tickets.
Front-end changes
Body theme
The body theme classes are now theme--highcontrast, theme--dark and/or theme--light.
jQuery update
jQuery was updated to v2.2. The most notable change is that $(document).ready(...) or $(...) for short fires sooner than before. Use the DOMContentLoaded event instead.
Search
The unified search replaces the traditional search input, hence OCA.Search became a noop. For backwards compatibility, the code will not raise any errors now, but it does not have any functionality.
Removed globals
escape-html: use the escape-html package <https://www.npmjs.com/package/escape-html> or similar
Deprecated global variables
humanFileSize: useformatfilesizefrom https://www.npmjs.com/package/@nextcloud/filesOC.getCanonicalLocale: usegetCanonicalLocalefrom https://www.npmjs.com/package/@nextcloud/l10n
Removed jQuery plugins
$.tipsy
Back-end changes
App bootstrap logic
The code that initializes an app or anything that should run for every request and command is now moved to a dedicated and typed API. The appinfo/app.php is therefore obsolete and deprecated. See bootstrapping for details.
PSR-3 integration
Nextcloud 20 is the first major release of Nextcloud that brings full compatibility with PSR-3: Logger Interface. From this point on it is highly recommended to use this interface mainly as the old \OCP\ILogger got deprecated with the last remaining changes. The majority of methods are identical between the Nextcloud-specific interface and the PSR one. Pay attention to usages of \OCP\ILogger::logException as that method does not exist on the PSR logger. However, you can specifcy an exception key in the $context argument of any \Psr\Log\LoggerInterface method and Nextcloud will format it like it did with the old logException.
PSR-11 integration
Nextcloud 20 is the first major release of Nextcloud that brings full compatibility with PSR-11: Container Interface. From this point on it is highly recommended to use this interface mainly as the old \OCP\IContainer got deprecated with this change.
The interfaces \OCP\AppFramework\IAppContainer and \OCP\IServerContainer will remain, but they won’t extend the IContainer anymore once that interface gets removed. As a result, IAppContainer and IServerContainer will eventually become tagging interfaces with the sole purpose of making it possible to have either the app or server container injected explicitly.
If your app requires Nextcloud 20 or later, you can replace any of the old type hints with one of \Psr\Container\ContainerInterface and replace calls of query with get, e.g. on the closures used when registering services:
// old
$container->registerService('DecryptAll', function (IAppContainer $c) {
return new DecryptAll(
$c->query('Util'),
$c->query(KeyManager::class),
$c->query('Crypt'),
$c->query(ISession::class)
)
})
becomes
// new
$container->registerService('DecryptAll', function (ContainerInterface $c) {
return new DecryptAll(
$c->get('Util'),
$c->get(KeyManager::class'),
$c->get('Crypt'),
$c->get(ISession::class)
)
})
Note
For a smoother transition, the old interfaces were changed so they are based on ContainerInterface, hence you can use has and get on IContainer and sub types.
Deprecated APIs
\OCP\IContainer: see PSR-11 integration\OCP\ILogger: see PSR-3 integration\OCP\IServerContainer::getEventDispatcher\OCP\IServerContainer::getCalendarManager: have the interface injected instead\OCP\IServerContainer::getCalendarResourceBackendManager: have the interface injected instead\OCP\IServerContainer::getCalendarRoomBackendManager: have the interface injected instead\OCP\IServerContainer::getContactsManager: have the interface injected instead\OCP\IServerContainer::getEncryptionManager: have the interface injected instead\OCP\IServerContainer::getEncryptionFilesHelper: have the interface injected instead\OCP\IServerContainer::getEncryptionKeyStorage: have the interface injected instead\OCP\IServerContainer::getRequest: have the interface injected instead\OCP\IServerContainer::getPreviewManager: have the interface injected instead\OCP\IServerContainer::getTagManager: have the interface injected instead\OCP\IServerContainer::getSystemTagManager: have the interface injected instead\OCP\IServerContainer::getSystemTagObjectMapper: have the interface injected instead\OCP\IServerContainer::getAvatarManager: have the interface injected instead\OCP\IServerContainer::getRootFolder\OCP\IServerContainer::getUserManager: have the interface injected instead\OCP\IServerContainer::getGroupManager: have the interface injected instead\OCP\IServerContainer::getUserSession: have the interface injected instead\OCP\IServerContainer::getSession: have the interface injected instead\OCP\IServerContainer::getTwoFactorAuthManager: have the interface injected instead\OCP\IServerContainer::getNavigationManager: have the interface injected instead\OCP\IServerContainer::getConfig: have the interface injected instead\OCP\IServerContainer::getSystemConfig: have the interface injected instead\OCP\IServerContainer::getAppConfig: have the interface injected instead\OCP\IServerContainer::getL10NFactory: have the interface injected instead\OCP\IServerContainer::getL10N: have the interface injected instead\OCP\IServerContainer::getURLGenerator: have the interface injected instead\OCP\IServerContainer::getAppFetcher: have the interface injected instead\OCP\IServerContainer::getMemCacheFactory: have the interface injected instead\OCP\IServerContainer::getGetRedisFactory: have the interface injected instead\OCP\IServerContainer::getDatabaseConnection: have the interface injected instead\OCP\IServerContainer::getActivityManager: have the interface injected instead\OCP\IServerContainer::getJobList: have the interface injected instead\OCP\IServerContainer::getLogger: have the interface injected instead\OCP\IServerContainer::getLogFactory: have the interface injected instead\OCP\IServerContainer::getRouter: have the interface injected instead\OCP\IServerContainer::getSearch: have the interface injected instead\OCP\IServerContainer::getSecureRandom: have the interface injected instead\OCP\IServerContainer::getCrypto: have the interface injected instead\OCP\IServerContainer::getHasher: have the interface injected instead\OCP\IServerContainer::getCredentialsManager: have the interface injected instead\OCP\IServerContainer::getCertificateManager: have the interface injected instead\OCP\IServerContainer::getHTTPClientService: have the interface injected instead\OCP\IServerContainer::createEventSource\OCP\IServerContainer::getEventLogger: have the interface injected instead\OCP\IServerContainer::getQueryLogger: have the interface injected instead\OCP\IServerContainer::getTempManager: have the interface injected instead\OCP\IServerContainer::getAppManager: have the interface injected instead\OCP\IServerContainer::getMailer: have the interface injected instead\OCP\IServerContainer::getWebRoot: have the interface injected instead\OCP\IServerContainer::getOcsClient: have the interface injected instead\OCP\IServerContainer::getDateTimeZone: have the interface injected instead\OCP\IServerContainer::getDateTimeFormatter: have the interface injected instead\OCP\IServerContainer::getMountProviderCollection: have the interface injected instead\OCP\IServerContainer::getIniWrapper: have the interface injected instead\OCP\IServerContainer::getCommandBus: have the interface injected instead\OCP\IServerContainer::getTrustedDomainHelper: have the interface injected instead\OCP\IServerContainer::getLockingProvider: have the interface injected instead\OCP\IServerContainer::getMountManager: have the interface injected instead\OCP\IServerContainer::getUserMountCache: have the interface injected instead\OCP\IServerContainer::getMimeTypeDetector: have the interface injected instead\OCP\IServerContainer::getMimeTypeLoader: have the interface injected instead\OCP\IServerContainer::getCapabilitiesManager: have the interface injected instead\OCP\IServerContainer::getNotificationManager: have the interface injected instead\OCP\IServerContainer::getCommentsManager: have the interface injected instead\OCP\IServerContainer::getThemingDefaults: have the interface injected instead\OCP\IServerContainer::getIntegrityCodeChecker: have the interface injected instead\OCP\IServerContainer::getSessionCryptoWrapper: have the interface injected instead\OCP\IServerContainer::getCsrfTokenManager: have the interface injected instead\OCP\IServerContainer::getBruteForceThrottler: have the interface injected instead\OCP\IServerContainer::getContentSecurityPolicyManager: have the interface injected instead\OCP\IServerContainer::getContentSecurityPolicyNonceManager: have the interface injected instead\OCP\IServerContainer::getStoragesBackendService: have the interface injected instead\OCP\IServerContainer::getGlobalStoragesService: have the interface injected instead\OCP\IServerContainer::getUserGlobalStoragesService: have the interface injected instead\OCP\IServerContainer::getUserStoragesService: have the interface injected instead\OCP\IServerContainer::getShareManager: have the interface injected instead\OCP\IServerContainer::getCollaboratorSearch: have the interface injected instead\OCP\IServerContainer::getAutoCompleteManager: have the interface injected instead\OCP\IServerContainer::getLDAPProvider: have the interface injected instead\OCP\IServerContainer::getSettingsManager: have the interface injected instead\OCP\IServerContainer::getAppDataDir\OCP\IServerContainer::getCloudIdManager: have the interface injected instead\OCP\IServerContainer::getGlobalScaleConfig: have the interface injected instead\OCP\IServerContainer::getCloudFederationProviderManager: have the interface injected instead\OCP\IServerContainer::getRemoteApiFactory: have the interface injected instead\OCP\IServerContainer::getCloudFederationFactory: have the interface injected instead\OCP\IServerContainer::getRemoteInstanceFactory: have the interface injected instead\OCP\IServerContainer::getStorageFactory: have the interface injected instead\OCP\IServerContainer::getGeneratorHelper: have the interface injected instead\OC_App::registerLogIn(): use bootstrapping and\OCP\AppFramework\Bootstrap\IRegistrationContext::registerAlternativeLoginEvent
\OCA\DAV\CalDAV\CalDavBackend::createCachedCalendarObject: listen to\OCA\DAV\Events\CachedCalendarObjectCreatedEventEvent
\OCA\DAV\CalDAV\CalDavBackend::createCalendar: listen to\OCA\DAV\Events\CalendarCreatedEventEvent
\OCA\DAV\CalDAV\CalDavBackend::createCalendarObject: listen to\OCA\DAV\Events\CalendarObjectCreatedEventEvent
\OCA\DAV\CalDAV\CalDavBackend::createSubscription: listen to\OCA\DAV\Events\SubscriptionCreatedEventEvent
\OCA\DAV\CalDAV\CalDavBackend::deleteCachedCalendarObject: listen to\OCA\DAV\Events\CachedCalendarObjectDeletedEventEvent
\OCA\DAV\CalDAV\CalDavBackend::deleteCalendar: listen to\OCA\DAV\Events\CalendarDeletedEventEvent
\OCA\DAV\CalDAV\CalDavBackend::deleteCalendarObject: listen to\OCA\DAV\Events\CalendarObjectDeletedEventEvent
\OCA\DAV\CalDAV\CalDavBackend::deleteSubscription: listen to\OCA\DAV\Events\SubscriptionDeletedEventEvent
\OCA\DAV\CalDAV\CalDavBackend::publishCalendar: listen to\OCA\DAV\Events\CalendarPublishedEventEvent
\OCA\DAV\CalDAV\CalDavBackend::publishCalendar: listen to\OCA\DAV\Events\CalendarUnpublishedEventEvent
\OCA\DAV\CalDAV\CalDavBackend::updateCachedCalendarObject: listen to\OCA\DAV\Events\CachedCalendarObjectUpdatedEventEvent
\OCA\DAV\CalDAV\CalDavBackend::updateCalendar: listen to\OCA\DAV\Events\CalendarUpdatedEventEvent
\OCA\DAV\CalDAV\CalDavBackend::updateCalendarObject: listen to\OCA\DAV\Events\CalendarObjectUpdatedEventEvent
\OCA\DAV\CalDAV\CalDavBackend::updateShares: listen to\OCA\DAV\Events\CalendarShareUpdatedEventEvent
\OCA\DAV\CalDAV\CalDavBackend::updateSubscription: listen to\OCA\DAV\Events\SubscriptionUpdatedEventEvent
\\OCA\DAV\CardDAV\CardDavBackend::createCard: listen to\OCA\DAV\Events\CardCreatedEventEvent
\OCA\DAV\CardDAV\CardDavBackend::deleteCard: listen to\OCA\DAV\Events\CardDeletedEventEvent
\OCA\DAV\CardDAV\CardDavBackend::updateCard: listen to\OCA\DAV\Events\CardUpdatedEventEvent
\OCA\Files_Sharing::loadAdditionalScripts:: publicShareAuth: listen to\OCA\Files_Sharing\Event\BeforeTemplateRenderedEventEvent
\OCA\Files_Sharing::loadAdditionalScripts: listen to\OCA\Files_Sharing\Event\BeforeTemplateRenderedEventEvent
\OCA\User_LDAP\User\User::postLDAPBackendAdded: listen to\OCA\User_LDAP\Events\UserBackendRegisteredEvent
\OCA\User_LDAP\User\User::postLDAPBackendAdded: listen to\OCA\User_LDAP\Events\GroupBackendRegisteredEvent
\OCP\AppFramework\Http\StandaloneTemplateResponse::EVENT_LOAD_ADDITIONAL_SCRIPT: listen to\OCP\AppFramework\Http\Events\BeforeTemplateRenderedEventEvent
\OCP\AppFramework\Http\StandaloneTemplateResponse::EVENT_LOAD_ADDITIONAL_SCRIPTS_LOGGEDIN: listen to\OCP\AppFramework\Http\Events\BeforeTemplateRenderedEventEvent
\OCP\WorkflowEngine::loadAdditionalSettingScripts: listen to\OCP\WorkflowEngine\Events\LoadSettingsScriptsEvent
Removed from public namespace
\OCP\IServerContainer::getAppFolderHook
\OCA\DAV\Connector\Sabre::authInit: use the\OCA\DAV\Events\SabrePluginAuthInitEventevent insteadEvent
\OC_User::post_removeFromGroup: listen to\OCP\Group\Events\UserRemovedEventEvent
\OCA\DAV\Connector\Sabre::authInit: listen to\OCA\DAV\Events\SabrePluginAuthInitEvent