Salesforce CanvasでVisualforceのページ名によってアプリケーションを動的に切り替える

# はじめに

`Visualforceのページ名によってアプリケーションを動的に切り替える`とはどういうことか？というと

本番環境やsandboxで表示するアプリケーションを1つのVisualforceで開発環境のものと本番環境のものとで切り替えたい。の手法の一つとして実装してみたものです。

:::note 
検証につかう環境は、trailheadのハンズオン環境です。
出てくるデータも初期のデモデータになります。
:::

# やらないこと

- 接続アプリケーションの作成手順

別の記事で作成手順を記載していますので、今回は特別記載しません

https://qiita.com/takaHAL/items/6fa0d76a4056045d76bc#%E6%8E%A5%E7%B6%9A%E3%82%A2%E3%83%97%E3%83%AA%E3%82%B1%E3%83%BC%E3%82%B7%E3%83%A7%E3%83%B3

- キャンバスアプリケーション側

今回は、キャンバスアプリケーション側のソースコードを触る必要はないため記載しません


以下の記事で作成したものをそのまま使ってます。

https://qiita.com/takaHAL/items/6fa0d76a4056045d76bc#%E6%8E%A5%E7%B6%9A%E3%82%A2%E3%83%97%E3%83%AA%E3%82%B1%E3%83%BC%E3%82%B7%E3%83%A7%E3%83%B3

https://qiita.com/takaHAL/items/9150fae5dce87c90ff3a

https://qiita.com/takaHAL/items/6caa83a199adcb7783cc

# やること

- キャンバスアプリケーション（本番）、キャンバスアプリケーション（開発）の作成
- Canvas用のVisualforceページを1つ作成
- アプリケーション切り替え用のApexの作成

完成イメージ

![無題の図形描画 (16).jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/445600/9ebdc501-4b1c-b662-722e-a8e9a4cc5c82.jpeg)

# キャンバスアプリケーション（本番）の準備

https://qiita.com/takaHAL/items/6fa0d76a4056045d76bc#%E6%8E%A5%E7%B6%9A%E3%82%A2%E3%83%97%E3%83%AA%E3%82%B1%E3%83%BC%E3%82%B7%E3%83%A7%E3%83%B3

以前作成した`canvasAppTest`というアプリケーションを使用します。


|項目|内容|
|---|---|
|接続アプリケーション名|キャンバスアプリテスト|
|API参照名|canvasAppTest|
|OAuth設定の有効化|チェック|
|コールバックURL|キャンバスアプリケーションのURL/callback|
|選択した OAuth 範囲|`フルアクセス`、`いつでも要求を実行`|
|キャンバス|チェック|
|キャンバスアプリケーションURL|埋め込みたいWebサイトURL|
|アクセス方法|署名付き要求（POST）|
|場所|Lightningコンポーネント、Visualforceページ|

# キャンバスアプリケーション（開発）の準備

前回の設定のAPI参照名とキャンバスアプリケーション名を変更して作成します。

|項目|内容|
|---|---|
|接続アプリケーション名|キャンバスアプリテスト（開発）|
|API参照名|Dev_canvasAppTest|

やる設定はほとんど同じなので、
実際同一の接続アプリケーションを流用して新規作成したい場合は、SalesforceDXでmetadataを落として xmlファイルを修正して再リリースするのが一番早いと思います。
その際に、`consumerKey`はSalesforceの全組織で一意であるため`consumerKey`を含めているとエラーが起きます。
xmlファイルから`consumerKey`を取り除くと問題なくリリースすることができます。

# Apexの作成

コードの完成系はこちら

```java: CanvasController.cls
public with sharing class CanvasController {
  public String canvasAppName = '';
  /**
   * Salesforceの環境によってprefixを付与した canvasAppName を返す
   */
  public String getCanvasAppName() {
    String pageName = ApexPages.currentPage()
      .getUrl()
      .substringBetween('apex/', '?');
    if (pageName == null) {
      pageName = ApexPages.currentPage().getUrl().substringAfter('apex/');
    }

    Organization org = [SELECT Id, IsSandbox FROM Organization LIMIT 1];
    if (org.IsSandbox) {
      this.canvasAppName = 'Dev_' + pageName;
    } else {
      this.canvasAppName = pageName;
    }

    return this.canvasAppName;
  }
}
```

以下でControllerとして呼び出している、VisualforceのURLから
ページ名を取得しています。

https://developer.salesforce.com/docs/atlas.ja-jp.apexcode.meta/apexcode/apex_system_pagereference.htm

`ApexPages.currentPage()
      .getUrl()`で`https://Salesforce_instance/apex/MyFirstPage?id=001D000000IRt53`という形式のURLが取得できます MyFirstPage ここの部分がVisualforceページ名になります

```java
String pageName = ApexPages.currentPage()
      .getUrl()
      .substringBetween('apex/', '?');
    if (pageName == null) {
      pageName = ApexPages.currentPage().getUrl().substringAfter('apex/');
    }
```

以下で組織情報からsandboxかどうかを判定し、sandboxの場合はページ名に'Dev_'のprefixを付与するようにしています。

```java
Organization org = [SELECT Id, IsSandbox FROM Organization LIMIT 1];
    if (org.IsSandbox) {
      this.canvasAppName = 'Dev_' + pageName;
    } else {
      this.canvasAppName = pageName;
    }
```

# Visualforceの作成

CanvasControllerから`canvasAppName`を取得し
apex:canvasAppの`applicationName`にセットすることで動的にアプリケーション名を変更しています。

```html: canvasAppTest.page
<apex:page controller="CanvasController">
  表示しているキャンバスアプリケーション：{!canvasAppName}
  <apex:canvasApp developerName="{!canvasAppName}" maxHeight="infinite" width="100%" />
</apex:page>
```

# Salesforce上で動作確認


## 本番

本番のアプリケーション想定である
canvasAppTestが表示されました。


![株式会社-Salesforce-Canvas-Salesforce (4).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/445600/23727fd9-f8c2-19f8-719f-8ae9a7acad5b.png)


## sandbox

sandboxに関しては、ハンズオン環境を用いて作成しているので同一環境での検証になるため、
今回は、Apexの分岐を反対にして検証します。

```diff_java
+   if (!org.IsSandbox) {
      this.canvasAppName = 'Dev_' + pageName;
    } else {
      this.canvasAppName = pageName;
    }
```

sandboxのアプリケーション想定である
Dev_canvasAppTestが表示されました。

![株式会社-Salesforce-Canvas-Salesforce (3).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/445600/a763a0df-eeba-4e55-3d5d-2defcdb5b9b6.png)

# 最後に

無事、Visualforceページ一個で2つのアプリケーションをSalesofrceの環境によって切り替えることができました！
今回は、ページ名ベースで切り替えましたがApexに渡すパラメータでを切り替えの起点にするとか
Devみたいなprefixをつけずにカスタムオブジェクトにマッピング表を作って、Apexでアプリケーション名をとってきてもいいと思います。

他にもこんな実装方法があるよ！等ありましたら教えていただけると幸いです。

# 参考

https://developer.salesforce.com/docs/atlas.ja-jp.pages.meta/pages/pages_compref_canvasApp.htm

https://salesforce.stackexchange.com/questions/178214/how-to-cover-apexpages-currentpage-geturl

https://developer.salesforce.com/docs/atlas.ja-jp.apexcode.meta/apexcode/apex_system_pagereference.htm