これは何?
この記事は「24日後に立派なSalesforceエンジニアになるWEBエンジニア Advent Calendar 2022」の23日目の記事です2日後に立派なSalesforceエンジニアになるために今日は昨日に引き続きVisualforceのコントローラの種類ということでカスタムコントローラとコントローラ拡張についてみていこうと思います。
カスタムコントローラとコントローラ拡張
どんな時に使うか
標準コントローラでは各オブジェクトに対してSalesforceが事前に用意しているアクションを指定することができたが、それ以外の処理をしたい場合はカスタムコントローラや拡張コントローラを使用する。
実行モードの違い
カスタムコントローラを使うと全てシステムモードで実行される。そのためカスタムコントローラを指定した場合は、現在のユーザの権限と項目レベルのセキュリティが適用されない。
一方拡張コントローラで標準コントローラを拡張した場合、ユーザモードで実行され、現在のユーザの権限、項目レベルのセキュリティ、および共有ルールが適用される。
どちらを使うべきか
カスタムコントローラとコントローラ拡張どちらを使うべきかは上述した実行モードの違いで判断するのが良い。
また拡張コントローラはその名の通り標準/カスタムコントローラの”拡張”なので、新しいアクションを追加したい場合や、標準コントローラのアクションを1つ上書きしたい時などには拡張コントローラを選択すると良いだろう。
カスタムコントローラ
カスタムコントローラの実態はApexクラスである。作成したカスタムコントローラはVisualforce内から以下のようにして呼び出すことができる。
<apex:page controller="MyCustomController">
</apex:page>
サンプル
カスタムコントローラの作成を参考にサンプルコードを見ていく。
public with sharing class MyCustomController {
private final Account account;
public MyCustomController() {
account = [SELECT Id, Name, Site, isPersonAccount FROM Account
WHERE Id = :ApexPages.currentPage().getParameters().get('id')];
}
public Account getAccount() {
return account;
}
public PageReference save() {
update account;
return null;
}
}
<apex:page controller="myCustomController" tabStyle="Account">
<apex:form>
<apex:pageBlock title="Congratulations {!$User.FirstName}">
You belong to Account Name: <apex:inputField value="{!account.name}"/>
<apex:commandButton action="{!save}" value="save"/>
</apex:pageBlock>
</apex:form>
</apex:page>
実行結果は以下のようになる。
ApexクラスでカスタムコントローラであるMyCustomController
を作成してVisualforce側から<apex:page controller="myCustomController">
で呼び出している。
コントローラ内ではURLからgetで渡されたidパラメータを受け取ってそれを元にAccountレコードを取得。
コントローラ内で取得したレコードは getter メソッドを通じてVisualforce側に渡される。今回の例で言うとVisualforceで{!account.name}
と書くことでコントローラのgetAccount()
メソッドが呼び出されて、取得したaccount
のname
項目が表示される。
コントローラ拡張
メインコントローラに機能を追加するときに使う。例えば標準コントローラに変数やメソッドを少しだけ追加したいときに、コントローラ拡張を使ってやれば、カスタムコントローラほどしっかりと処理を作り込まなくても、意図した変数やメソッドやだけを追加すると言うことができる。
またメインコントローラは1つのページにつき1つしか定義できないのに対して、コントローラ拡張は複数定義することができる。
コントローラ拡張の定義は以下のように記述する。
<apex:page standardController="MainController"
extensions="myControllerExtension1,myControllerExtension2">
</apex:page>
サンプル
カスタムコントローラ同様にコントローラ拡張についてもサンプルを見ていく。
public class MyControllerExtension {
private final Account acct;
// 初期化の処理で、標準コントローラからgetRecordを使って取引先の情報を取得しておく
public MyControllerExtension(ApexPages.StandardController stdController) {
this.acct = (Account)stdController.getRecord();
}
public String getGreeting() {
return 'Hello ' + acct.name + ' (' + acct.id + ')';
}
}
<apex:page standardController="Account" extensions="myControllerExtension">
{!greeting} <p/>
<apex:form>
<apex:inputField value="{!account.name}"/> <p/>
<apex:commandButton value="Save" action="{!save}"/>
</apex:form>
</apex:page>
Apexクラスで拡張コントローラとなるMyControllerExtension
を作成してVisualforce側から標準取引先コントローラと合わせて<apex:page standardController="Account" extensions="myControllerExtension">
のような形でコントローラの拡張を行なっている。
コントローラからVisualforceへの値の渡し方は今までと同じで getter を用意してVisualforce側で{!greeting}
のように書くとコントローラのgetGreeting()
メソッドが呼び出される。
サンプル(拡張コントローラを複数定義)
メインコントローラは1つしか指定できないが、拡張コントローラは複数指定することができるので、その時の挙動についてみていく。
public class ExtOne {
public ExtOne(ApexPages.StandardController acon) { }
public String getFoo() {
return 'foo-One';
}
}
public class ExtTwo {
public ExtTwo(ApexPages.StandardController acon) { }
public String getFoo() {
return 'foo-Two';
}
public String getBar() {
return 'bar-Two';
}
}
<apex:page standardController="Account"
extensions="ExtOne,ExtTwo" showHeader="false">
<apex:outputText value="{!foo}" />
<apex:outputText value="{!bar}" />
</apex:page>
これを実行すると以下のような画面になる。
{!foo}
を表示するためのgetFoo
はExtOne,ExtTwoどちらの拡張にもメソッドが書かれているが、その場合はextensions="ExtOne,ExtTwo"
のリストで左(はじめ)に定義したもので上書きされることがわかる。
また{!bar}
を表示するgetBar
はExtTwoにしかないが、この場合はそのメソッドがそのまま呼び出される。
最後に
Visualforceを触り始めた時は標準コントローラが便利で基本的にはそれを使おうと思っていたものの、やはり実際の運用をしていくとそれでは実装しきれないものも出てくるので、そういった時にはカスタムコントローラやコントローラ拡張を使えるようになっていると良さそうです。
明日は24日クリスマスイブということでクリスマス感溢れるSalesforce組織を作っていこうと思います。