Salesforce 標準コントローラと標準リストコントローラでできること

# これは何？
この記事は「[24日後に立派なSalesforceエンジニアになるWEBエンジニア Advent Calendar 2022](https://qiita.com/advent-calendar/2022/kakakaori)」の22日目の記事です3日後に立派なSalesforceエンジニアになるために今日はVisualforceのコントローラの種類と、その中でも標準コントローラと標準リストコントローラについてみていこうと思います。

# コントローラの種類
Visualforceについて調べているとコントローラ周りでは以下のような言葉が出てくる。
- 標準コントローラ
- 標準リストコントローラ
- カスタムコントローラ
- コントローラ拡張

# メインコントローラ
Visualforceでページを作るときにはまずメインコントローラを定義する。そのメインコントローラは上記のうち以下の3つの中から1つを選んで定義する。
- 標準コントローラ
- 標準リストコントローラ
- カスタムコントローラ

## 標準コントローラ
標準コントローラは以下のように記述して利用する。
```html:
<apex:page standardController="MyCustomObject__c">
</apex:page>
```
URLでidパラメータを指定すると、そのレコードIDのオブジェクトを取得してきてそこにいろんな処理ができるようになる。
```
https://Salesforce_instance/apex/myPage?id=001x000xxx3Jsxb
```
上記URLでアクセスされたページで標準コントローラに取引先の標準コントローラを指定している場合は、取引先の中でレコードID`001x000xxx3Jsxb`を探してきて、そのレコードに対して処理ができるようになる。

### データへのアクセス
Visualforce内では標準コントローラを使うことでそのレコードの項目にアクセスすることができる。
```html:
<apex:page standardController="Account">
  {!account.name} 
</apex:page>
```
これで取引先オブジェクトの名前項目を表示することができる。

#### 子から親のレコードを参照する
`{!contact.Account.Owner.FirstName}`とすることで親に遡った上でその項目を参照することができる。

#### 親から子のレコードを参照する
`{!account.Contacts}`とすることで今表示している取引先に紐づく全ての取引先責任者データを参照することができる。これらは配列で返される。

### アクション処理
オブジェクトに対する基本的な処理として用意されている処理は以下の通り。
| メソッド | 内容 |処理完了後の動き |
|:-|:-|:-|
| save  |  新規レコードの作成もしくはレコードの更新を行う。|元のページか、保存したレコードの詳細ページに遷移する。 |
| quicksave  |  saveと同じ。| 画面の遷移は発生しない。 |
| edit  | レコードの編集ページに遷移させる。  |ユーザがアクションを呼び出したページに遷移する。|
|  delete |  レコードを削除する。 |ページを更新するか、関連づけられたオブジェクトのタブにユーザを移動する。|
| cancel  | 編集操作を中止する。  |ユーザがアクションを呼び出したページに遷移する。|
| list  | そのオブジェクトに対して最近使用されたリスト検索条件に基づいて、標準リストページの PageReference オブジェクトを返す。  | - |

これらのメソッドは`action`パラメータに対して`{!アクション名}`を指定することで呼び出すことができる。
```html:test.page
<apex:page standardController="Account">
  <apex:form>
    <apex:pageBlock title="My Content" mode="edit">
      <apex:pageBlockButtons>
        <apex:commandButton action="{!save}" value="Save"/>
      </apex:pageBlockButtons>
      <apex:pageBlockSection title="My Content Section" columns="2">
        <apex:inputField value="{!account.name}"/>
        <apex:inputField value="{!account.site}"/>
        <apex:inputField value="{!account.type}"/>
        <apex:inputField value="{!account.accountNumber}"/>
      </apex:pageBlockSection>
    </apex:pageBlock>
  </apex:form>
</apex:page>
```
例えば上記のような場合はこのような画面が生成され、`apex:commandButton`の`action`で`save`が指定されているので、このボタンを押すとレコードの保存が走るようになる。
![スクリーンショット 2022-12-19 10.58.16.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/200812/58a79bd8-29dd-7f8c-e738-5e8385ae0b7c.png)

## 標準リストコントローラ
先ほど触れた標準コントローラは1レコードを対象にしているのに対して、標準リストコントローラは複数レコードが対象になる。
標準コントローラの指定に加えて`recordSetVar`属性を付与することで利用することができる。

```html:
<apex:page standardController="MyCustomObject__c" recordSetVar="records">
</apex:page>
```
サンプルコードを実装してみる。
```html:
<apex:page standardController="Account" recordSetVar="accounts" tabstyle="account" sidebar="false">
  <apex:pageBlock>
    <apex:pageBlockTable value="{!accounts}" var="acc">
      <apex:column value="{!acc.name}"/>
    </apex:pageBlockTable>
  </apex:pageBlock>
</apex:page>
```
例えば上記のような場合はこのような画面が生成される。
![スクリーンショット 2022-12-19 12.01.59.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/200812/4368da2d-28ea-f78c-c488-a8baf3141151.png)
`recordSetVar="accounts"`で取得してきたAccountのリストを`accounts`に入れて、`<apex:pageBlockTable>`を使って表を表示する。
このとき`value="{!accounts}"`とすることで`accounts`を表示する内容として指定し、ループで回したときの1レコードを`var="acc"`で`acc`に入れておくような感じ。


### アクション処理
リストコントローラーで使用できる処理は以下の通り。
| メソッド | 内容 |処理完了後の動き |
|:-|:-|:-|
| save  |  新規レコードの作成もしくはレコードの更新を行う。|元のページか、保存したレコードの詳細ページに遷移する。 |
| quicksave  |  saveと同じ。| 画面の遷移は発生しない。 |
| cancel  | 編集操作を中止する。  |ユーザがアクションを呼び出したページに遷移する。|
| list  | ユーザが`filterId`を指定していない場合は、そのオブジェクトに対して最近使用されたリスト検索条件に基づいて、標準リストページの PageReference オブジェクトを返す。  | - |
| first  | セットにあるレコードの最初のページを表示する。  |  - |
| last  |  セットにあるレコードの最後のページを表示する。 |  - |
| next  |  セットにあるレコードの次のページを表示する。 |  - |
|  previous | セットにあるレコードの前のページを表示する。  | -  |

`next`と`previous`はページャを作るときに使う。こんな感じ。
```html:
<apex:pageBlockButtons>
  <apex:commandButton action="{!previous}" value="前へ"/>
  <apex:commandButton action="{!next}" value="次へ"/>
</apex:pageBlockButtons>
```
先ほどの画面に簡単にページャを入れることができた。
![スクリーンショット 2022-12-19 21.12.34.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/200812/ae555f31-e552-b9bb-a03d-43cd45712372.png)

# 最後に
今日はVisualforceの標準コントローラと標準リストコントローラについてみていきました。
これをうまく使えば基本的な画面についてはコード量も少なく実装ができて便利そうです。
明日はカスタムコントローラとコントローラ拡張についてみていきます。