公式ドキュメントを読んでいて、コントローラ拡張っていうのは、標準コントローラーを拡張するのが主な用途なのかな?と思ったので、標準コントローラの拡張をやってみました。
【Apex+Visualforce】コントローラ拡張の用途。標準ボタン、標準リンクの上書き。
アクションの追加
まず前提として、標準コントローラーで提供されるアクションは下記です。
標準コントローラで提供されるアクション(公式サイト)
保存(save)や編集(edit)、削除(delete)などの標準的なアクションですね。
アクションが実行された後の挙動も決まっています。
ここで、標準コントローラーでは提供されていないやり直し(redo)というアクションを追加したい場合(やり直しボタンを押すと、画面で編集中の内容が取り消されて初期表示の状態に戻る)。
こんな感じで実装します。
まずはコントローラークラス。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 |
/** 取引先の標準コントローラー拡張 */ public class AccountExtensionsController { /** 取引先 */ public Account acct{get; set;} /** * コンストラクタ. * @param stdController 標準コントローラ */ public AccountExtensionsController(ApexPages.StandardController stdController) { this.acct = (Account)stdController.getRecord(); } /** * やり直しボタン押下時. * ※標準コントローラには無いactionの追加. */ public void redo() { Account acct = [ SELECT id, Name, Phone, Fax, Description FROM Account WHERE Id =: this.acct.Id ]; this.acct.Name = acct.Name; this.acct.Phone = acct.Phone; this.acct.Fax = acct.Fax; this.acct.Description = acct.Description; } } |
続いてVisualforce画面。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
<!-- 取引先の標準コントローラーを使用した、取引先入力画面 --> <apex:page standardController="Account" extensions="AccountExtensionsController"> <apex:form > <apex:pageBlock > <apex:pageBlockSection title="取引先情報"> <apex:inputField value="{!Account.id}" /> <apex:inputField value="{!Account.Name}" /> <apex:inputField value="{!Account.Phone}" /> <apex:inputField value="{!Account.Fax}" /> <apex:inputField value="{!Account.Description}" /> </apex:pageBlockSection> <apex:pageBlockButtons > <apex:commandButton value="保存" action="{!save}"/> <apex:commandButton value="やり直し" action="{!redo}"/> </apex:pageBlockButtons> </apex:pageBlock> </apex:form> </apex:page> |
やり直しボタンを押すと、こんな感じの挙動になります。

アクションの上書き
続いて、もともと標準コントローラーに備わっているアクションに機能を追加したい場合。
今回は、保存時に「説明(Account.Description)」が未入力だった場合、”(自動入力)”という文字列を自動で設定するという動きを追加することにします。
こんな感じですね。

Javaとかで言うとオーバーライド的な発想ですが、実装的にはオーバーライドとは違うので”上書き”という言葉を使いました。
コントローラークラスの実装例はこんな感じです。
redoアクションを追加した時のソースとの差分をハイライトしてます。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 |
public class AccountExtensionsController { /** 取引先 */ public Account acct{get; set;} /** 標準コントローラー */ private ApexPages.StandardController stdController; /** * コンストラクタ. * @param stdController 標準コントローラ */ public AccountExtensionsController(ApexPages.StandardController stdController) { this.stdController = stdController; this.acct = (Account)stdController.getRecord(); } /** * やり直しボタン押下時. * ※標準コントローラには無いActionの追加. */ public void redo() { Account acct = [ SELECT id, Name, Phone, Fax, Description FROM Account WHERE Id =: this.acct.Id ]; this.acct.Name = acct.Name; this.acct.Phone = acct.Phone; this.acct.Fax = acct.Fax; this.acct.Description = acct.Description; } /** * 保存ボタン押下時. * ※標準コントローラに存在するAction. */ public PageReference save() { if (String.isEmpty(this.acct.Description)) { this.acct.Description = '(自動入力)'; } return this.stdController.save(); } } |
ポイントとしては45行目です。
標準コントローラーでも提供されているsaveメソッドと同じ名前のメソッドを作ったので(41行目)、標準コントローラのsaveメソッドは実行されずに、上記拡張クラスのsaveメソッドが実行されます。
でも今回やりたかったのは標準コントローラの保存処理の前に少し処理を追加したかっただけなので(42~44行目)、標準コントローラのsaveメソッドも処理したい。なので45行目のコードになっています。
補足
ちなみに標準コントローラのsaveメソッドは、保存時に画面遷移する仕様となっています。
保存した際に画面遷移したくないのであればquicksaveメソッドを使います。
標準コントローラで提供されるアクション(公式サイト)
しかし!ApexPages.StandardControllerクラスにはquicksaveメソッドがない。
StandardControllerクラス(公式サイト)
作っておいてくれてもいいのに・・
とりあえず下記のように実装すればquicksaveと同じような(たぶん同じ)動きになります。
まずはコントローラ。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 |
public class AccountExtensionsController { /** 取引先 */ public Account acct{get; set;} /** 標準コントローラー */ private ApexPages.StandardController stdController; /** * コンストラクタ. * @param stdController 標準コントローラ */ public AccountExtensionsController(ApexPages.StandardController stdController) { this.stdController = stdController; this.acct = (Account)stdController.getRecord(); } /** * やり直しボタン押下時. * ※標準コントローラには無いActionの追加. */ public void redo() { Account acct = [ SELECT id, Name, Phone, Fax, Description FROM Account WHERE Id =: this.acct.Id ]; this.acct.Name = acct.Name; this.acct.Phone = acct.Phone; this.acct.Fax = acct.Fax; this.acct.Description = acct.Description; } /** * 保存ボタン押下時. * ※標準コントローラに存在するAction. */ public void quicksave() { if (String.isEmpty(this.acct.Description)) { this.acct.Description = '(自動入力)'; } this.stdController.save(); } } |
次にVisualforce画面。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
<apex:page standardController="Account" extensions="AccountExtensionsController"> <apex:form > <apex:pageBlock > <apex:pageBlockSection title="取引先情報"> <apex:inputField value="{!Account.id}" /> <apex:inputField value="{!Account.Name}" /> <apex:inputField value="{!Account.Phone}" /> <apex:inputField value="{!Account.Fax}" /> <apex:inputField value="{!Account.Description}" /> </apex:pageBlockSection> <apex:pageBlockButtons > <apex:commandButton value="保存" action="{!quicksave}"/> <apex:commandButton value="やり直し" action="{!redo}"/> </apex:pageBlockButtons> </apex:pageBlock> </apex:form> </apex:page> |
コメント