Fiori Elements V2 のコントローラ拡張機能を UI5 の最新化に対応させます。次のような場合に使用します: - 拡張コントローラが `sap.ui.controller()` を使用し、マニフェストに対応する `controllerName` エントリがある場合(Case B → 報告のみ、最新化しない) - 拡張コントローラが `Controller.extend()` を使用し、マニフェストで `controllerName` として登録されている場合(Case B → 報告のみ、最新化しない) - コードに `registerControllerExtensions` の呼び出しが含まれている場合(Case A → ControllerExtension.extend を使用して処理を上書き) - Manifest.json に `sap.ui5/extends/extensions/sap.ui.controllerExtensions` があり、`controllerName` エントリが含まれている場合 **重要なポイント:** Case B(プレーンオブジェクト形式)が最も一般的です。Case B の場合は、コントローラファイルを**変更せず**に報告して進めてください。Case A の場合のみ、実際のコード最新化が必要です。 カスタムアプリ(Fiori Elements 以外)の標準的なコントローラ定義で、`sap.ui.controller()` がスタンドアロンコントローラを定義しているだけの場合は、代わりに `fix-js-globals`(Case 9)を使用してください。
Handle Fiori Elements V2 controller extensions during UI5 modernization. Use this skill when: - Extension controllers use `sap.ui.controller()` AND the manifest has a matching `controllerName` entry (Case B → report only, do not modernize) - Extension controllers use `Controller.extend()` with manifest `controllerName` registration (Case B → report only, do not modernize) - Code contains `registerControllerExtensions` calls (Case A → ControllerExtension.extend + override) - Manifest.json has `sap.ui5/extends/extensions/sap.ui.controllerExtensions` with `controllerName` entries Case B (plain object) is by far the most common. For Case B, do NOT modify controller files — report them and move on. Case A requires actual code modernization. For plain controller definitions in custom (non-Fiori-Elements) apps where `sap.ui.controller()` is just defining a standalone controller, use `fix-js-globals` (Case 9) instead.
This skill handles Fiori Elements V2 controller extensions during UI5 modernization. There are two cases with different actions:
controllerName in manifest → Report only. Do NOT modify the controller files. Leave them as-is and inform the user which files need manual attention.registerControllerExtensions → Perform the full modernization to ControllerExtension.extend() + manifest registration.| Rule ID | Message Pattern | This Skill's Action |
|---|---|---|
no-deprecated-api |
Use of deprecated registerControllerExtensions |
Case A: Modernize to manifest + ControllerExtension |
no-deprecated-api |
Use of deprecated sap.ui.controller |
Case B (if manifest has controllerName): report only, do not fix; Case A (if registerControllerExtensions): ControllerExtension class |
no-deprecated-api |
Use of deprecated Controller (from sap/ui/core/mvc/Controller) |
Case B: report only, do not fix |
Is there a `controllerName` entry in manifest.json under
sap.ui5/extends/extensions/sap.ui.controllerExtensions with a SIMPLE key
(no "#" in the key)?
├── YES → Case B: DO NOT MODERNIZE. Report the file(s) and move on.
│ (regardless of whether source uses sap.ui.controller() or Controller.extend())
└── NO → Is there a registerControllerExtensions call in JS?
├── YES → Case A: modernize to ControllerExtension.extend() + manifest with #stableId key
└── NO → This skill does not apply
Case B (most common) — Detected when the manifest already has a controllerName entry under a simple key, and the controller file uses either sap.ui.controller() or Controller.extend():
// manifest.json — controllerName registration already present (simple key, no "#")
"sap.ui.controllerExtensions": {
"sap.suite.ui.generic.template.ListReport.view.ListReport": {
"controllerName": "my.app.ext.controller.ListReportExt"
}
}
The source controller might look like either of these:
// Variant 1: sap.ui.controller() — NO sap.ui.define wrapper
sap.ui.controller("my.app.ext.controller.ListReportExt", {
onInit: function() { ... },
onCustomAction: function() { ... }
});
// Variant 2: Controller.extend() — inside sap.ui.define
sap.ui.define(["sap/ui/core/mvc/Controller", ...], function(Controller, ...) {
return Controller.extend("my.app.ext.controller.ListReportExt", { ... });
});
Linter output triggering Case B:
MyExtension.controller.js:1:1 error Use of deprecated function 'sap.ui.controller' no-deprecated-api
MyExtension.controller.js:3:5 error Use of deprecated function 'Controller' (from 'sap/ui/core/mvc/Controller') no-deprecated-api
Action for Case B: Do NOT modify these files. Report them to the user and continue with the rest of the modernization.
Case A (rare, older apps only) — Apply when you see linter output like:
Component.js:25:5 error Use of deprecated function 'registerControllerExtensions' no-deprecated-api
Or when an app has patterns like:
// In Component.js or elsewhere — NO manifest entry exists yet
this.getExtensionComponent().registerControllerExtensions("sap.suite.ui.generic.template.ListReport.view.ListReport", {
onInit: function() { ... },
onAction: function() { ... }
});
The action depends on how the extension is registered in the manifest. Determine which case applies before proceeding.
| Manifest Registration | Source Code (any of) | Action |
|---|---|---|
controllerName in manifest (simple key, no #stableId) |
sap.ui.controller(), Controller.extend(), or plain object |
Case B: Report only — do NOT modify files |
registerControllerExtensions in JS (no manifest entry) |
sap.ui.controller() or inline object |
Case A: ControllerExtension.extend() + override + add manifest entry with #stableId key |
The key differentiator is the manifest registration format:
controllerName already in manifest under a simple key (e.g., "sap.suite.ui.generic.template.ListReport.view.ListReport": { "controllerName": "..." }). Do not modernize these files. Report them and move on.controllerName in manifest yet — extension is registered programmatically via registerControllerExtensions. The modernization adds a manifest entry with the #stableId key format AND uses ControllerExtension.extend().Detection commands:
# Check manifest registration format
grep -B1 -A2 "controllerName" webapp/manifest.json
# Case B indicator: controllerName in manifest with simple key (no # in key)
# If the key does NOT contain "#", it's the merging mechanism → Case B → REPORT ONLY
# Case A indicator: registerControllerExtensions in JS
grep -rl "registerControllerExtensions" webapp/ --include="*.js"
For extensions registered via controllerName in the manifest (simple key without #stableId), do NOT modify the controller files. These require careful manual modernization and are left to the developer.
Steps:
controllerName entries in manifest.json (under keys that do NOT contain #)⚠️ Fiori Elements controller extensions (Case B) — skipped, requires manual modernization:
- webapp/ext/controller/ListReportExt.controller.js
- webapp/ext/controller/ObjectPageExt.controller.js
These files use deprecated APIs (sap.ui.controller / Controller.extend) but are Fiori Elements
controller extensions registered via controllerName in the manifest. They require careful manual
modernization to a plain-object return pattern. The linter errors for these files will persist until
they are modernized manually.
fix-js-globals replacing sap.ui.getCore() calls within method bodies, fix-linter-blind-spots for namespace patterns). Only the sap.ui.controller() / Controller.extend() structure itself is left untouched.Only for Case A (extensions using registerControllerExtensions in JS).
Move controller extension registrations from JavaScript code to the manifest under sap.ui.controllerExtensions.
Key format: <FLOORPLAN_CONTROLLER>#<STABLE_ID_OF_VIEW>
// Before - no controller extensions in manifest
// After - manifest.json
{
"sap.ui5": {
"extends": {
"extensions": {
"sap.ui.controllerExtensions": {
"sap.suite.ui.generic.template.ListReport.view.ListReport#myApp::sap.suite.ui.generic.template.ListReport.view.ListReport::EntitySet": {
"controllerName": "my.app.ext.ListReportExtension"
},
"sap.suite.ui.generic.template.ObjectPage.view.Details#myApp::sap.suite.ui.generic.template.ObjectPage.view.Details::EntitySet": {
"controllerName": "my.app.ext.ObjectPageExtension"
}
}
}
}
}
}
Finding the correct key:
<FloorplanController>#<StableViewId>sap.suite.ui.generic.template.ListReport.view.ListReport)<AppId>::<FloorplanViewName>::<EntitySet>sap.ui.generic.app / pages configuration to find entity sets and page IDs⚠️ This step only applies to Case A (extensions using
sap.ui.controller()factory). If the extension already usesController.extend()with manifestcontrollerNameregistration, use Case B below instead.
Convert controller files from sap.ui.controller style to ControllerExtension class.
Before:
sap.ui.controller("my.app.ext.ListReportExtension", {
onInit: function() {
// lifecycle code
},
onBeforeRebindTable: function(oEvent) {
// framework override
},
onCustomAction: function(oEvent) {
// custom method
}
});
After:
sap.ui.define([
"sap/ui/core/mvc/ControllerExtension"
], function(ControllerExtension) {
"use strict";
return ControllerExtension.extend("my.app.ext.ListReportExtension", {
// Lifecycle and framework overrides go inside "override"
override: {
onInit: function() {
// extensionAPI is injected by the framework into the extension instance
this._extensionAPI = this.extensionAPI;
},
onBeforeRebindTable: function(oEvent) {
// framework override
}
},
// Custom methods go OUTSIDE "override"
onCustomAction: function(oEvent) {
// custom method
}
});
});
Key rules for restructuring:
sap/ui/core/mvc/ControllerExtension instead of using sap.ui.controlleronInit, onExit, onBeforeRendering, onAfterRendering) → inside overrideonBeforeRebindTable, onBeforeRebindChart, onListNavigationExtension, adaptNavigationParameterExtension, etc.) → inside overrideoverrideextensionAPI via this.extensionAPI (the framework injects it into the extension instance)In the manifest and XML annotations, update all event handler references from the old format to the new qualified format.
Before:
// In manifest extensions or annotations
"Actions": {
"MyAction": {
"id": "MyAction",
"text": "Do Something",
"press": "onCustomAction"
}
}
After:
"Actions": {
"MyAction": {
"id": "MyAction",
"text": "Do Something",
"press": ".extension.my.app.ext.ListReportExtension.onCustomAction"
}
}
Reference format: .extension.<full.controller.name>.<methodName>
Important: Use the dotted module name as declared in ControllerExtension.extend("my.app.ext.ListReportExtension", ...) and in the manifest's controllerName — not the slash-separated path used in sap.ui.define imports (e.g., "my/app/ext/ListReportExtension").
This applies to:
press handlers in manifest action definitionscontrollerName in manifest (simple key, no #)registerControllerExtensions calls in the codebase (typically in Component.js or helper files)manifest.json under sap.ui5/extends/extensions/sap.ui.controllerExtensionssap.ui.controller(...) with sap.ui.define([ControllerExtension], ...)
b. Move lifecycle/framework methods into override section
c. Keep custom methods outside override
d. Update extensionAPI access patternpress handlers using simple method names
b. Search XML annotation files for handler references
c. Update to .extension.<module>.<method> formatregisterControllerExtensions calls from Component.jsBefore — Component.js:
sap.ui.define([
"sap/suite/ui/generic/template/lib/AppComponent"
], function(AppComponent) {
"use strict";
return AppComponent.extend("my.app.Component", {
metadata: {
manifest: "json"
},
init: function() {
AppComponent.prototype.init.apply(this, arguments);
this.getExtensionComponent().registerControllerExtensions(
"sap.suite.ui.generic.template.ListReport.view.ListReport", {
onInit: function() {
// lifecycle code
},
onCustomAction: function(oEvent) {
// custom handler
}
}
);
}
});
});
After — Component.js:
sap.ui.define([
"sap/suite/ui/generic/template/lib/AppComponent"
], function(AppComponent) {
"use strict";
return AppComponent.extend("my.app.Component", {
metadata: {
manifest: "json"
}
// registerControllerExtensions call removed — now in manifest.json
});
});
After — manifest.json (additions):
{
"sap.ui5": {
"extends": {
"extensions": {
"sap.ui.controllerExtensions": {
"sap.suite.ui.generic.template.ListReport.view.ListReport#my.app::sap.suite.ui.generic.template.ListReport.view.ListReport::Products": {
"controllerName": "my.app.ext.ListReportExtension"
}
}
}
}
}
}
After — ext/ListReportExtension.controller.js:
sap.ui.define([
"sap/ui/core/mvc/ControllerExtension"
], function(ControllerExtension) {
"use strict";
return ControllerExtension.extend("my.app.ext.ListReportExtension", {
override: {
onInit: function() {
this._extensionAPI = this.extensionAPI;
}
},
onCustomAction: function(oEvent) {
// Custom action handler — accessible as
// ".extension.my.app.ext.ListReportExtension.onCustomAction"
}
});
});
sap.suite.ui.generic.template)sap.fe.templates) uses a different extension mechanism — this skill does not applycontrollerName in the manifest. These are not auto-modernized — the agent reports them and moves onregisterControllerExtensionstemplateSpecific.json for handler references, those must also be updated (Case A only)sap.ui.controller() definitions in custom apps (Case 9), or if extension controllers also use global access patterns (sap.ui.getCore(), jQuery.sap.*). Other skills CAN still be applied to Case B controller files for issues unrelated to the controller extension pattern itself (e.g., replacing global API usage within method bodies).原文・著作権は Anthropic および各プラグイン作者に帰属します。日本語訳は Claude API による自動翻訳です。