Apexを活用したSalesforceナレッジのプログラマティックな管理ガイド

背景と応用シナリオ

Salesforce Developer (Salesforce 開発者) の皆様、こんにちは。本日は、多くの組織でカスタマーサポートとセルフサービスの基盤となっている Salesforce Knowledge (Salesforce ナレッジ) について、開発者の視点から深く掘り下げていきたいと思います。Salesforce Knowledgeは、顧客、パートナー、そして社内従業員が必要な情報を迅速かつ容易に見つけられるようにするための強力なナレッジベースソリューションです。

標準機能だけでも非常に高機能ですが、ビジネスプロセスが複雑化するにつれて、ナレッジ記事のライフサイクルをプログラムで制御したいという要求は増え続けています。例えば、以下のようなシナリオが考えられます。

応用シナリオ

  • 外部CMSとの連携: 外部のコンテンツ管理システム (CMS) で作成されたコンテンツを、API経由でSalesforceナレッジ記事として自動的に作成または更新する。
  • プロセスの自動化: 特定の条件を満たしたケースがクローズされる際に、その解決策を元にナレッジ記事の下書きを自動生成する。
  • カスタムUIの構築: 標準のナレッジコンポーネントでは満たせない要件に対応するため、独自の検索機能や表示形式を持つ Lightning Web Component (LWC) を構築し、記事データを動的に取得・表示する。
  • 一括処理: 古くなった記事を特定のルールに基づいて一括でアーカイブしたり、製品のバージョンアップに伴い、関連する多数の記事を一度に更新して新しいバージョンとして公開したりする。

これらのシナリオを実現するためには、Salesforce Knowledgeのデータモデルと、それを操作するためのApexコードについての深い理解が不可欠です。この記事では、Apexを用いてナレッジ記事をどのようにプログラマティックに管理できるかを、具体的なコード例と共に解説していきます。


原理の説明

Apexでナレッジ記事を操作する前に、その根幹となるデータモデルと主要なApexクラスを理解することが重要です。

データモデル:Knowledge__kav と Knowledge__ka

Salesforce Knowledgeのデータモデルは、一見すると少し特殊に見えます。中心となるオブジェクトは2つです。

  • Knowledge__ka (Knowledge Article): これは記事の「マスター」となるオブジェクトです。各記事に一意のレコードが存在し、記事番号 (Article Number) などを管理しますが、実際のコンテンツ(タイトル、本文など)は保持しません。
  • Knowledge__kav (Knowledge Article Version): こちらが記事のバージョンを管理するオブジェクトであり、開発者が主に操作する対象となります。タイトル、本文、カスタム項目といった記事のコンテンツはすべてこのオブジェクトに格納されます。同じ記事(同一のKnowledge__ka)に対して、「下書き(Draft)」「公開(Online)」「アーカイブ済み(Archived)」といった異なるバージョンのレコードが存在します。

この構造により、公開中のバージョンに影響を与えることなく、新しいバージョンの下書きを編集したり、過去のバージョンをアーカイブとして保持したりすることが可能になっています。SOQLクエリで記事を検索する際は、通常Knowledge__kavオブジェクトを対象とし、PublishStatus項目でバージョンを絞り込みます。

記事タイプからレコードタイプへ

Salesforce Classicのナレッジでは「記事タイプ」という独自の仕組みで記事のテンプレートを管理していましたが、Lightning Experienceでは標準オブジェクトと同様にRecord Type (レコードタイプ) を使用します。これにより、開発者はより馴染み深い方法で記事のレイアウトや選択リスト値を制御できるようになりました。

プログラマティックなアクセス:KbManagement 名前空間

ナレッジ記事のライフサイクル(公開、アーカイブ、翻訳など)を操作するために、Salesforceは専用のApexクラス群をKbManagement名前空間で提供しています。

単純な項目の更新であれば、Knowledge__kavオブジェクトに対して通常のDML (Data Manipulation Language) 操作(update)を実行できます。しかし、記事を「下書き」から「公開済み」へ変更するような状態遷移は、単にPublishStatus項目を更新するだけでは実行できません。このような操作には、KbManagement.PublishingServiceクラスを使用する必要があります。このクラスには、以下のような重要なメソッドが含まれています。

  • publishArticle(articleId, flagAsNew): 指定したIDの記事を公開します。
  • archiveArticle(articleId, unpublish): 公開中の記事をアーカイブします。
  • editOnlineArticle(articleId, unpublish): 公開中の記事を編集するための新しい下書きバージョンを作成します。

これらの専用メソッドを使用することで、Salesforceが内部で行うべき処理(バージョン管理、フィード投稿、インデックス更新など)が正しく実行されることが保証されます。


示例代码

ここでは、特定のナレッジ記事の最新の下書きバージョンを検索し、それを公開するApexクラスの例を示します。このコードは、Salesforceの公式ドキュメントで紹介されているKbManagement.PublishingServiceクラスの利用方法に基づいています。

public class KnowledgeManager {

    /**
     * @description 指定された記事番号を持つ記事の最新バージョンを公開するメソッド
     * @param articleNumber 公開したい記事の記事番号 (例: 'kA000000001')
     * @return Boolean 公開が成功した場合はtrue、失敗した場合はfalse
     */
    public static Boolean publishLatestDraftByArticleNumber(String articleNumber) {
        // 記事番号を元に、最新の下書きバージョンを検索
        // KnowledgeArticleVersion オブジェクト (API名: Knowledge__kav) をクエリします。
        // PublishStatus = 'Draft' で下書き状態のバージョンのみを対象とします。
        // IsLatestVersion = true で、その記事の最新バージョンであることを保証します。
        // ArticleNumber はマスターである KnowledgeArticle (Knowledge__ka) の項目ですが、
        // リレーションを介して Knowledge__kav から直接クエリできます。
        List<Knowledge__kav> draftsToPublish = [
            SELECT Id, Title, KnowledgeArticleId 
            FROM Knowledge__kav 
            WHERE ArticleNumber = :articleNumber 
            AND PublishStatus = 'Draft' 
            AND IsLatestVersion = true 
            LIMIT 1
        ];

        if (draftsToPublish.isEmpty()) {
            // 公開対象の下書きが見つからない場合
            System.debug('公開対象の記事番号 ' + articleNumber + ' の下書きバージョンが見つかりませんでした。');
            return false;
        }

        // 公開対象の KnowledgeArticleId を取得
        // KbManagement.PublishingService.publishArticle メソッドは、
        // Knowledge__kav の ID ではなく、親である Knowledge__ka の ID を引数に取ります。
        Id knowledgeArticleId = draftsToPublish[0].KnowledgeArticleId;
        System.debug('記事ID: ' + knowledgeArticleId + ' の公開を試みます。');

        try {
            // KbManagement.PublishingService を使って記事を公開
            // 第2引数 (flagAsNew) を true に設定すると、公開時に新しいバージョンとして扱われます。
            // 通常、下書きから公開する場合は true を指定します。
            KbManagement.PublishingService.KnowledgePublishResult result = KbManagement.PublishingService.publishArticle(knowledgeArticleId, true);

            if (result.isSuccess()) {
                // 公開が成功した場合
                System.debug('記事の公開に成功しました。新しいバージョンID: ' + result.getArticleVersionId());
                return true;
            } else {
                // 公開が失敗した場合のエラー処理
                for (KbManagement.PublishingService.PublishingServiceError error : result.getErrors()) {
                    System.debug('エラーコード: ' + error.getStatusCode());
                    System.debug('エラーメッセージ: ' + error.getMessage());
                }
                return false;
            }
        } catch (Exception e) {
            // 予期せぬ例外の処理
            System.debug('記事の公開中に例外が発生しました: ' + e.getMessage());
            return false;
        }
    }
}

このコードを匿名実行ウィンドウで呼び出すには、以下のようにします。

// 存在する記事番号に置き換えてください
Boolean success = KnowledgeManager.publishLatestDraftByArticleNumber('kA000000001'); 
System.debug('公開処理の結果: ' + success);

注意事項

ナレッジ記事をプログラムで操作する際には、いくつかの重要な注意点があります。

権限とライセンス

  • ナレッジユーザーライセンス: コードを実行するユーザーには「Knowledge User」ライセンスが割り当てられている必要があります。
  • オブジェクト権限: ユーザーのプロファイルまたは権限セットで、Knowledgeオブジェクト(Knowledge__kav)に対する適切なCRUD(作成、参照、更新、削除)権限が必要です。
  • 記事アクション権限: 記事を公開またはアーカイブするには、アプリケーション権限である「記事の管理」権限、および記事アクションを通じて割り当てられた公開やアーカイブの権限が必要です。これらの権限が不足していると、コードはSystem.NoAccessExceptionをスローする可能性があります。

APIの制限とガバナ制限

  • ガバナ制限: KbManagementクラスのメソッドも、他のApexトランザクションと同様に、SOQLクエリの回数やDMLステートメントの数などのガバナ制限に従います。多数の記事を一括で処理する場合は、コードをバルク対応させることが不可欠です。
  • 非同期処理: 記事の公開プロセスは、内部的に非同期で実行されることがあります。メソッド自体は同期的に結果を返しますが、組織内のインデックス更新や可視性の反映にはわずかな遅延が生じる場合があります。

エラー処理

KbManagement.PublishingServiceのメソッドは、失敗しても例外をスローするとは限りません。代わりに、isSuccess()falseを返す結果オブジェクトを返します。したがって、必ず戻り値を確認し、getErrors()メソッドを使って具体的なエラー内容を取得・ログ記録する堅牢なエラー処理を実装することが重要です。エラーの例としては、必須項目が入力されていない、承認プロセスが有効になっている、などが考えられます。

テストクラスの実装

ナレッジ関連のコードをテストする際は、テストデータを作成する必要があります。テストメソッド内でKnowledge__kavレコードを作成し、そのレコードを対象にロジックをテストします。ただし、KbManagementの一部のメソッドは(SeeAllData=true)を指定しないと動作しない場合があります。可能な限りテスト分離を維持するため、テストデータ作成を優先し、ドキュメントで(SeeAllData=true)が必須とされている場合にのみ使用を検討してください。


まとめとベストプラクティス

Salesforce Developerとして、Apexを利用してSalesforce Knowledgeをプログラマティックに操作する能力は、複雑なビジネス要件を満たすための強力な武器となります。

本記事で解説した内容の要点は以下の通りです。

  • ナレッジのデータモデルは、マスターのKnowledge__kaとバージョンのKnowledge__kavから構成される。
  • 記事のライフサイクル操作(公開、アーカイブなど)には、標準DMLではなく、専用のKbManagement名前空間のクラスを使用する。
  • コードを実行するユーザーの権限とライセンス設定は、成功の前提条件である。
  • メソッドの戻り値を常にチェックし、堅牢なエラー処理を実装することが不可欠である。

ベストプラクティス

  1. 適切なメソッドの選択: 記事のライフサイクルを操作する際は、必ずKbManagement.PublishingServiceなどの専用クラスを使用してください。PublishStatus項目を直接DMLで更新しようとしないでください。
  2. コードのバルク化: 複数の記事を一度に処理する可能性がある場合は、必ずリストでIDを収集し、ループの外で一括処理を行うことでガバナ制限を回避してください。
  3. データモデルの理解: クエリを記述する際は、PublishStatusIsLatestVersionLanguageなどの主要な項目を適切に利用して、意図した通りのバージョンを取得するようにしてください。
  4. 宣言的アプローチとの併用: すべてをApexで実装する必要はありません。Flowや承認プロセスといった宣言的なツールとApexを組み合わせることで、よりメンテナンスしやすく、効率的なソリューションを構築できます。

Salesforce Knowledgeの自動化と連携は、組織のナレッジ活用を新たなレベルへと引き上げます。本記事が、その一助となれば幸いです。

コメント