【Salesforce】【Aura】Auraコンポーネントでファイルをアップロードする

レコード詳細画面のボタン押下でダイアログを表示し、レコードに紐づけてファイル登録を行う方法を２つ検証したので書いていきます。
**①標準コンポーネントの File Upload  を使用する**
**②標準コンポーネントの Input（タイプ "file"）を使用する**

①はアップロードから登録までを一括してくれるコンポーネントです。とりあえずファイルをしたいときはこれを使えば簡単です。
②はファイルアップロードのためのコンポーネントです。（Input自体はテキストや日時などの入力に使われます。）
　読込・登録は別で処理を書く必要がありますが、ファイル名チェックなどの中間処理を入れることが可能です。

#仕様
・商談のレコード詳細ページにファイル登録ボタンを配置する
・ボタン押下でファイル登録ダイアログを表示する
・ファイルをアップロードすると商談に紐づく形で登録し、ダイアログを閉じる
というような仕様は統一で
　①はアップロードから登録まで連続。.txtと.xlsxの拡張子を許容し、ファイルの複数選択が可能。
　②はアップロードと登録を分割。.pdfを許容し、複数選択が不可。ファイル名に「請求書」が含まれるかチェックする。
というようにしました。

#下準備 AuraコンポーネントとApexクラスの新規作成
開発者コンソールでAuraコンポーネントを新規作成します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1461666/4b383e67-75d9-ac19-fc08-7d266d563169.png)
　File　→　New　→　Lightning Component
FileUploadAction1とFileUploadAction2を作成しました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1461666/b56b4d99-74ed-0b79-e02a-4983dbdc306f.png)
ついでにカスタムコントローラーも作成します。
　File　→　New　→　Apex Class
FileUploadActionContollerを作成しました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1461666/a05b1a4a-5dc6-c71a-e3b6-9159474821d8.png)

#下準備 アクション作成と配置
Salesforce設定画面で商談レコード詳細ページにボタンを作成します。
　オブジェクトマネージャー　→　商談　→　ボタン、リンク、およびアクション　→　新規アクション
ファイル登録1とファイル登録2を作成しました。
Lightning コンポーネントには先ほど作成したFileUploadAction1とFileUploadAction2をそれぞれ設定します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1461666/c7560edf-1395-8a6f-f0bb-e9eceb7402af.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1461666/fe4ec809-e0c9-b56e-dacc-341c1a6dc5f8.png)

これだけでは画面に表示されないので注意です。
ページレイアウトに作成したアクションを配置して保存します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1461666/5d741af8-5ba4-bc08-3e63-dc54550c71f8.png)


これで下準備完了です。
レコード詳細ページにボタンが表示されました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1461666/6accca3e-2951-a2a0-63d5-621f7a8f51b5.png)

この状態ではまだ何も書いていない状態なので、ボタンを押しても空のダイアログが表示されるだけです。
それではコードを書いていきましょう！


#①File Upload  を使用する
ここで必要なのはAuraコンポーネントのコンポーネント部分とJavaScriptで書かれるコントローラ部分のみです。

```FileUploadAction1.cmp
<aura:component implements="force:lightningQuickActionWithoutHeader,force:hasRecordId">
    <aura:attribute name="recordId" type="String"/>
    <article class="slds-card">
        <div class="slds-page-header" role="banner">
            <h1 class="slds-page-header__title">ファイル登録１</h1>
        </div>
        <br/>
    	<lightning:fileUpload 
            label="請求書添付"
   	        name="fileUploader"
            multiple="true"
            accept=".txt,.xlsx"
            recordId="{!v.recordId}"
            onuploadfinished="{!c.handleUploadFinished}" />       
    </article>
</aura:component>
```

lightning:fileUpload がアップロードも登録もしてくれる便利なやつです。
multipleでファイルの複数選択が可能か否かを定義します。
acceptは許容するファイルの拡張子を設定します。複数指定したいときはカンマ区切りで書きます。

```FileUploadAction1Contoller.js
({
    handleUploadFinished: function (cmp, event) {
        var uploadedFiles = event.getParam("files");
        alert(uploadedFiles.length + "個のファイルを登録しました。");
        $A.get("e.force:closeQuickAction").fire();
        $A.get('e.force:refreshView').fire();
    }
})
```



handleUploadFinishedはとりあえず入れとけなので入れています。
今回は登録件数を表示するようにしました。

【実際の動作】ダイアログ表示
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1461666/8f638afb-33e9-8975-4589-27e3f29fa072.png)
【実際の動作】アップロード
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1461666/15edef69-884e-ff63-9e73-e8ecb8e9a0f7.png)
【実際の動作】登録完了
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1461666/ff437099-bd45-57be-769b-ed05801bdb7f.png)

無事に登録できました！！
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1461666/4f7d849d-6c03-c62b-fb3c-cfb9a048d80b.png)



#②Input  を使用する
これはちょっと増えます。

```FileUploadAction2.cmp
<aura:component implements="force:lightningQuickActionWithoutHeader,force:hasRecordId" controller="FileUploadActionContoller">
    <aura:attribute name="recordId" type="String"/>
    <aura:attribute name="hasFile" type="Boolean" default="false"/>
    <aura:attribute name="fileMessage" type="String"/>
    <aura:attribute name="file" type="Object"/>
    <article class="slds-card">
        <div class="slds-page-header" role="banner">
            <h1 class="slds-page-header__title">ファイル登録２</h1>
        </div>
        <br/>
        <aura:if isTrue="{!v.hasFile}">
            <h2 class="slds-card__file-title name">{!v.fileMessage}</h2>
            <ui:button class="slds-button slds-button--neutral" press="{!c.saveFile}" label="登録" />
            <aura:set attribute="else">
                <lightning:input name="file1" type="file" label="請求書添付" multiple="fales" accept=".pdf" onchange="{! c.handleFilesChange }"/>
                <h2 class="slds-card__file-title error">{!v.fileMessage}</h2>
            </aura:set>
        </aura:if>
        <br/>
        <ui:button class="slds-button slds-button--neutral" press="{!c.cancel}" label="キャンセル" />
    </article>
</aura:component>
```
controller="FileUploadActionContoller"でApexのコントローラを設定します。
fileはtype="Object"です。ここにアップロードしたファイルの情報が入ります。

```FileUploadAction2Contoller.js
({
    saveFile : function(component, event, helper) {
        helper.saveFile(component);
    },
    cancel : function(component, event, helper) {
        $A.get("e.force:closeQuickAction").fire();
    },
    handleFilesChange : function (component, event, helper) {
        helper.checkFileName(component,event);
    }
})
```
ボタン・操作で呼ばれるファイル登録、キャンセル、ファイル変更のアクションです。

```FileUploadAction2Helper.js
({
    checkFileName: function(component, event) {
        var files = event.getSource().get("v.files");
        if(files[0].name.includes("請求書")) {
            component.set("v.hasFile", true);
            component.set("v.fileMessage", files[0].name);
            component.set("v.file", files[0]);
        }else{
            component.set("v.hasFile", false);
            component.set("v.fileMessage", "ファイル名が不正です: " + files[0].name );
        }
    },
    saveFile: function(component) {
        var recordId = component.get("v.recordId");
        var file = component.get("v.file");
        var reader  = new FileReader();
        reader.onload = function() {                    
            var fileContent = reader.result;
            var base64 = 'base64,';
            var dataStart = fileContent.indexOf(base64) + base64.length;
            fileContent = fileContent.substring(dataStart);
            var action = component.get("c.insertContentVersion");
            action.setParams({
                recordId : recordId,
                base64Data : encodeURIComponent(fileContent),
                fileName : file.name
            });
            $A.enqueueAction(action);
            
        }
        reader.readAsDataURL(file);
        
        $A.get("e.force:closeQuickAction").fire();
        $A.get('e.force:refreshView').fire();

    }
})
```
ヘルパーにより詳しい処理を書きます。
checkFileNameではファイル名に「請求書」が含まれるかチェックしています。
saveFileではファイル読み込みを行い、ApexのFileUploadActionContollerに処理を渡します。

```FileUploadAction2.css
.THIS .slds-card__file-title.name {
    font-weight: normal;
    font-size: x-large;
}
.THIS .slds-card__file-title.error {
    font-weight: bold;
    font-size: medium;
    color: red;
    margin-top: 0.5rem;
    margin-bottom: 0.5rem;
}
```
いい感じに表示を整えます。
詳しくないので間違っていたら教えてください、、、

```FileUploadActionContoller.cls
public class FileUploadActionContoller {
    
    /**
     * ファイルを登録する
     */
    @AuraEnabled
    public static void insertContentVersion(String recordId, String base64Data, String fileName){
        base64Data = EncodingUtil.urlDecode(base64Data, 'UTF-8');
        ContentVersion cv = new ContentVersion(
            Title = fileName,
            VersionData = EncodingUtil.base64Decode(base64Data),
            PathOnClient = '/' + fileName,
            FirstPublishLocationId = recordId
        );
        insert cv;
    }

}
```
Auraコンポーネントで使用するメソッドには @AuraEnabled をつける必要があります。

【実際の動作】ダイアログ表示
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1461666/3266e73e-0813-5687-bf54-b59cdb3c59cd.png)
【実際の動作】アップロードNG
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1461666/237a0e8c-0852-de83-4e2c-80bfca141c6f.png)
【実際の動作】アップロードOK
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1461666/affa3cc6-90b4-4f8b-73ca-64fafb312c9e.png)

登録ボタンを押して、、こちらも無事に登録できました！！
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1461666/39a55de4-7ac3-d3bf-ef0b-dc2b4da6262c.png)

#参考
https://developer.salesforce.com/docs/component-library/bundle/lightning:input/example#lightningcomponentdemo:exampleInputFile

https://developer.salesforce.com/docs/component-library/bundle/lightning:fileUpload/documentation