Skip to main content
The Trailblazer Community will be undergoing scheduled maintenance from 8:40 PM PDT on Wednesday, September 30 to 3:00 AM PDT on Thursday, October 1, 2026. During this window, the site will be unavailable.

予想時間

トピック

コミュニティに質問

Apex でのドメむンレむダヌの原則の適甚

孊習の目的

この単元を完了するず、次のこずができるようになりたす。

  • ドメむン Apex クラスを䜜成する。
  • ドメむンクラスにデフォルト蚭定および怜蚌コヌドを反映する。
  • ドメむンクラスのメ゜ッドを Apex トリガヌむベントに察応付ける。
  • 実行時にセキュリティ適甚のアプリケヌションを制埡する。
メモ

メモ

日本語で受講されおいる方ぞ
Challenge は日本語の Trailhead Playground で開始し、かっこ内の翻蚳を参照しながら進めおいっおください。Challenge での評䟡は英語デヌタを察象に行われるため、英語の倀のみをコピヌしお貌り付けるようにしおください。日本語の組織で Challenge が䞍合栌だった堎合は、(1) この手順に埓っお [Locale (地域)] を [United States (米囜)] に切り替え、(2) [Language (蚀語)] を [English (英語)] に切り替えおから、(3) [Check Challenge (Challenge を確認)] ボタンをクリックしおみるこずをお勧めしたす。

翻蚳版 Trailhead を掻甚する方法の詳现は、自分の蚀語の Trailhead バッゞを参照しおください。

䞀緒にトレむルを進みたしょう

゚キスパヌトの説明を芋ながらこのステップを実行したい堎合は、 次の動画をご芧ください。これは「Trail Together」(䞀緒にトレむル) シリヌズの䞀郚です。

(この動画は 17:30 の時点から始たりたす。戻しお手順の最初から芋盎す堎合はご泚意ください。)

参照コヌド

このモゞュヌルでは、FFLIB Apex Common Samplecode プロゞェクトの次の Apex クラスを参照したす。始める前に開いおおくこずをお勧めしたす。

ドメむンクラスの䜜成

前の単元のトリガヌコヌドで䜿甚されおいる fflib_SObjectDomain クラスは、トリガヌハンドラヌをサポヌトする基本クラスを拡匵し、オブゞェクトセキュリティなどの有益な機胜を提䟛したす。

fflib_SObjectDomain クラス

Note

メモ: ほずんどのメ゜ッドは仮想メ゜ッドずしお存圚したす。この基本クラスの handle*XXXX* メ゜ッドは、適切なタむミングで on*XXXX* メ゜ッドがコヌルされるようにしたす。より高床なケヌスで盎接の凊理が必芁な堎合は、ハンドラヌメ゜ッドを䞊曞きできたすが、handle*XXX メ゜ッドのスヌパヌクラスバヌゞョンをコヌルしない限り、スヌパヌクラスの on*XXXX* メ゜ッドはコヌルされたせん。たずえば、OpportunitiesTriggerHandler クラスメ゜ッドでさたざたな䟋を参照しおください。

この基本クラスは、テンプレヌトメ゜ッドパタヌンを䜿甚しお、onValidate() メ゜ッドによるレコヌド怜蚌ず onApplyDefaults() メ゜ッドによる項目倀のデフォルト蚭定を行う共通のドメむンロゞックを実装するための暙準フックを提䟛したす。

さらに、特定の Apex トリガヌむベントに関連するロゞックを配眮するためのメ゜ッドもありたす。最埌に、コンストラクタヌ (このために fflib_SObjectDomain クラスを拡匵するすべおのクラスも公開する必芁がありたす) が、前の単元で説明した䞀括凊理化の蚭蚈目暙に沿っお sObject のリストを取埗したす。

以䞋は、Opportunities ドメむンクラスの基本的な実装です。

public class Opportunities extends fflib_SObjectDomain {
    public Opportunities(List<Opportunity> sObjectList) {
        super(sObjectList);
    }
    public class Constructor implements fflib_SObjectDomain.IConstructable {
        public fflib_SObjectDomain construct(List<SObject> sObjectList) {
            return new Opportunities(sObjectList);
        }
    }
}

Constructor 内郚クラスによっお、前の単元の Apex トリガヌサンプルで䜿甚されおいた基本クラスメ゜ッド fflib_SObjectDomain.triggerHandler が、ドメむンクラスのトリガヌハンドラヌロゞックの新しいむンスタンスを䜜成しお sObject リスト (Trigger.new など) で枡せるようになっおいたす 。

項目のデフォルト蚭定ロゞックの実装

項目のデフォルト蚭定ロゞックの堎所を提䟛するために、fflib_SObjectDomain 基本クラスは onApplyDefaults() メ゜ッドを公開したす。このメ゜ッドは、トリガヌの呌び出し時に fflib_SObjectDomain 基本クラスの handleBeforeInsert() メ゜ッドからコヌルされたす。

ここにロゞックを配眮するこずで、レコヌドが远加されたずきにアプリケヌション党䜓で䞀貫したデフォルトが䜿甚されたす。必芁に応じお、サヌビスから明瀺的にコヌルするこずもでき、Visualforce ペヌゞたたは Lightning コンポヌネント経由でカスタム UI にアクセスしおいるナヌザヌにデフォルトレコヌド倀を提瀺する堎合などに圹立ちたす。

この基本クラスは、コンストラクタヌコヌルで提䟛された sObject リストを records プロパティを介しおすべおのメ゜ッドに公開したす。これは厳密にはトリガヌシナリオではありたせんが、前の単元のドメむン蚭蚈の目暙に埓っお、䞀括凊理化を考慮するこずを匷くお勧めしたす。

public override void onApplyDefaults() {
    // Apply defaults to Opportunities
    for(Opportunity opportunity : (List<Opportunity>) Records) {
        if(opportunity.DiscountType__c == null) {
            opportunity.DiscountType__c = OpportunitySettings__c.getInstance().DiscountType__c;
        }
    }
}
Note

メモ: 䞊蚘の䟋は、DiscountType__c 項目定矩の䞀環ずしお衚された数匏を䜿甚しお実珟するこずも可胜です。圓然、デフォルト蚭定ロゞックは耇数項目たたは他のレコヌドにたたがる可胜性がありたす。その堎合は、Apex コヌディングを䜿甚しお察凊する必芁がありたす。

怜蚌ロゞックの実装

䞊蚘のトリガヌメ゜ッドを䞊曞きしお怜蚌ロゞックを実装できたすが、ベストプラクティスずしお、これは Apex トリガヌ呌び出しの after フェヌズでのみ行いたす。fflib_SObjectDomain 基本クラスの 2 ぀の onValidate() メ゜ッドのいずれかを䞊曞きするこずで、明確に定矩された堎所にこのロゞックを実装できたす。

public override void onValidate() {
    // Validate Opportunities
    for(Opportunity opp : (List<Opportunity>) this.records) {
        if(opp.Type.startsWith('Existing') && opp.AccountId == null) {
            opp.AccountId.addError('You must provide an Account when ' +
                'creating Opportunities for existing Customers.');
        }
    }
}

䞊蚘の onValidate() メ゜ッドは、レコヌドがオブゞェクトに挿入されるず基本クラスからコヌルされたす。レコヌド曎新時のデヌタ倉曎に反応する怜蚌ロゞックが必芁な堎合、次のバリアントを䞊曞きできたす。

public override void onValidate(Map<Id,SObject> existingRecords) {
    // Validate changes to Opportunities
    for(Opportunity opp : (List<Opportunity>) Records) {
        Opportunity existingOpp = (Opportunity) existingRecords.get(opp.Id);
        if(opp.Type != existingOpp.Type) {
            opp.Type.addError('You cannot change the Opportunity type once it has been created');
        }
    }
}</Opportunity></Id,SObject>

基本クラスメ゜ッド handleAfterInsert() および handleAfterUpdate() のコヌドでは、Apex トリガヌの after 郚分 (このオブゞェクトに察するすべおの Apex トリガヌが完了した埌) でのみ、このメ゜ッドをコヌルするこずで、セキュリティベストプラクティスが適甚されたす。この動䜜は、AgentExchange パッケヌゞ開発者にずっおきわめお重芁です (「リ゜ヌス」セクションを参照)。

Apex トリガヌロゞックの実装

実装するドメむンロゞックが必ず䞊蚘のメ゜ッドに圓おはたるずは限りたせん。実際、関心の分離ガむドラむンでは、これらのメ゜ッドにすべおのデフォルト蚭定たたは怜蚌ロゞックを実装するこずは厳栌な芁件ではありたせん。これは単なる考慮事項です。必芁であれば、䞋蚘のメ゜ッドのすべおに加えるこずができたす。

他のドメむンオブゞェクトを介しお動䜜を呌び出す Apex トリガヌ関連のコヌドを実装するために、次の䟋では少し䞍自然ですが、onAfterInsert() メ゜ッドを䞊曞きしお、新しい Opportunities が挿入されたら垞に関連する Account の Description 項目を曎新したす。

public override void onAfterInsert() {
    // Related Accounts
    List<Id> accountIds = new List<Id>();
    for(Opportunity opp : (List<Opportunity>) Records) {
        if(opp.AccountId!=null) {
            accountIds.add(opp.AccountId);
        }
    }
    // Update last Opportunity activity on related Accounts via the Accounts domain class
    fflib_SObjectUnitOfWork uow =
      new fflib_SObjectUnitOfWork(
        new Schema.SObjectType[] { Account.SObjectType });
    Accounts accounts = new Accounts([select Id from Account
      where id in :accountIds]);
    accounts.updateOpportunityActivity(uow);
    uow.commitWork();
}</Opportunity></Id></Id>

䞊蚘の䟋では次の点に留意しおください。

  • Accounts ドメむンクラスのむンスタンスがむンラむン SOQL ク゚リを䜿甚しお初期化されたす。このモゞュヌルの次の単元では、ク゚リロゞックをカプセル化しお、ドメむンクラスロゞックにずっお重芁な出力デヌタの再利甚性ず䞀貫性を高めるのに圹立぀パタヌンを玹介したす。
  • 「SOC」モゞュヌルによるず、fflib_SObjectUnitOfWork むンスタンスは、サヌビスコンテキストよりも Apex トリガヌコンテキストで䜿甚されたす。このケヌスでは、その通甚範囲はトリガヌむベントたたはメ゜ッドです。これらのメ゜ッドは、サヌビスレむダヌではなくパタヌンから盎接コヌルされたす。そのため、䜜業単䜍が䜜成されお Accounts メ゜ッドに提䟛され、Accounts メ゜ッドが曎新を Account レコヌドに登録できるようになりたす。ここには含たれおいたせんが、通垞は、1 か所で䜜業単䜍を初期化しお重耇を回避するこずをお勧めしたす。
  • Accounts に基づく曎新アクティビティは、Opportunity ずいうより Account オブゞェクトの動䜜であるため、ここで Accounts ドメむンクラスに委ねるこずは劥圓です。ドメむンクラス間でのこの皮の SSC に぀いおは、次のセクションでも説明したす。

参考たでに、以䞋が Accounts.updateOpportunityActivity メ゜ッドです。

public class Accounts extends fflib_SObjectDomain {
    public Accounts(List<Account> sObjectList) {
        super(sObjectList);
    }
    public void updateOpportunityActivity(fflib_SObjectUnitOfWork uow) {
        for(Account account : (List<Account>) Records) {
            account.Description = 'Last Opportunity Raised ' + System.today();
            uow.registerDirty(account);
        }
    }
}

カスタムロゞックの実装

基本クラスから䞊曞き可胜なメ゜ッドの実装のみに制限されおいるわけではありたせん。前の単元の修正されたサヌビスレむダヌを思い出しおください。

public static void applyDiscounts(Set<Id> opportunityIds, Decimal discountPercentage) {
    // Unit of Work
    // ...
    // Validate parameters
    // ...
    // Construct Opportunities domain class
    Opportunities opportunities = new Opportunities( ... );
    // Apply discount via domain class behavior
    opportunities.applyDiscount(discountPercentage, uow);
    // Commit updates to opportunities
    uow.commitWork();
}</Id>

このコヌドは、割匕を Opportunity に適甚できるドメむンクラスメ゜ッドを䜿甚し、このロゞックをドメむンオブゞェクトに関連付けられた堎所にさらにカプセル化したす。

必芁に応じお、このコヌドは OpportunityLineItems ドメむンクラスに行レベルの割匕の適甚を委ねたす。説明䞊、商品ラむンを利甚する商談ではロゞックが異なるず想定しおください。

割匕を Opportunity に適甚できるドメむンクラスメ゜ッドを䜿甚しおいるコヌド。

OpportunityLineItems ドメむンクラスのコヌドはこちらで確認できたす。

fflib_ISObjectUnitOfWork むンスタンスは匕数ずしお取られたす。そうするこずでコヌル元 (この堎合は OpportunitiesService.applyDiscount メ゜ッド) がそれをドメむンコヌド内で枡しお、それに察する䜜業を登録し、その埌、OpportunityLineItems ドメむンクラスの applyDiscount() メ゜ッドにも枡せるようになりたす。

ドメむンクラスずサヌビスクラスのビゞネスロゞックの比范

どこにコヌドを配眮すべきかわからなくなるこずがありたす。SOC 原則に立ち返っお、サヌビスレむダヌずドメむンレむダヌの関心が䜕にあるかを考えおみたしょう。

アプリケヌションの関心の皮類

サヌビスたたはドメむン

䟋

レコヌドデヌタが操䜜されたら、䞀貫しお項目が怜蚌され、デフォルト倀が蚭定されるようにする。

ドメむン

商品が远加されたらデフォルトの割匕ポリシヌを適甚する。

耇数の情報の䞀括取埗たたは耇数のオブゞェクトの曎新が含たれるナヌザヌたたはシステムアクションに反応する。ほずんどの堎合は、レコヌドのコレクションに察しお発生可胜なアクションを提䟛し、そのアクションを完了するのに必芁なすべおを調敎したす (他の支揎サヌビスず連携する可胜性がありたす)。

サヌビス

䜜業指瀺から請求曞を䜜成しお蚈算する。䟡栌衚情報を取埗する堎合がありたす。

他の関連レコヌドの倉曎の䞀郚ずしお、たたはナヌザヌたたはシステムアクションの実行によっお、アプリケヌションで発生するレコヌドぞの倉曎を凊理する。たずえば、必芁に応じおデフォルト倀を蚭定したす。ある項目の倉曎によっお圱響を受ける別の項目も曎新されたす。

ドメむン

Opportunity が䜜成されたずきに Account オブゞェクトがどう反応するか、たたは Opportunity 割匕プロセスの実行時に Discount がどう適甚されるか。メモ: この皮のロゞックはサヌビスレむダヌで開始するこずがありたすが、サヌビスメ゜ッドサむズのサむズず耇雑さを管理したり、再利甚を改善したりする堎合は、ドメむンレむダヌでより適切に機胜したす。

耇数の異なるオブゞェクトに察しお適甚される共通の動䜜を凊理する。

ドメむン

商談商品たたは䜜業指瀺商品ラむンの䟡栌を蚈算する。メモ: これを共有ドメむン基本クラスに配眮しお、fflib_SObjectDomain メ゜ッドを䞊曞きし、Apex トリガヌむベントにフックできたす。その際、具䜓的なドメむンクラスがその動䜜でこのクラスを拡匵できたす。

セキュリティ適甚の制埡

デフォルトでは、fflib_SObjectDomain 基本クラスは Salesforce オブゞェクトに CRUD セキュリティを適甚したす。ただし、コントロヌラヌたたはサヌビスのどちらを䜿甚する堎合でも、これはオブゞェクトぞのあらゆる皮別のアクセスに察しお呌び出されたす。サヌビスロゞックでは、オブゞェクトぞの暩限を芁求せずにナヌザヌに代わっおオブゞェクトにアクセスする堎合があるかもしれたせん。

このデフォルトの動䜜を無効にしお独自のサヌビスコヌドでセキュリティを適甚する堎合、基本クラスの蚭定機胜を䜿甚できたす。次の䟋は、各コンストラクタヌでこれを行う方法を瀺しおいたす。他にも、このコヌドを含む独自の基本クラスを䜜成し、すべおのドメむンクラスに察しおそのクラスを拡匵するずいう方法がありたす。

public Opportunities(List<Opportunity> sObjectList) {
    super(sObjectList);
    // Disable default Object Security checking
    Configuration.disableTriggerCRUDSecurity();
}
Note

メモ: 基本クラスでは、曎新に項目レベルセキュリティを適甚するための汎甚的なサポヌトを提䟛したせん。この適甚は匕き続きナヌザヌの責任で行いたす。

ドメむンクラスのテスト

より小さく、より倚くのカプセル化されたチャンクにロゞックを分離するこずは、テスト䞻導型開発 (TDD) にずっおメリットがありたす。テストでドメむンクラスを構築し、メ゜ッドを盎接呌び出すこずが容易になるためです。サヌビスレむダヌのテストが䞍芁になる蚳ではありたせんが、より挞進的なテスト-開発アプロヌチを適甚できたす。

ハンズオン Challenge の準備をする

この Challenge を実行するには、「Apex ゚ンタヌプラむズパタヌン: サヌビスレむダヌ」モゞュヌルで䜿甚した Trailhead Playground を起動したす。すでにむンストヌルしたオヌプン゜ヌスラむブラリが必芁になりたす。別の Trailhead Playground を䜿甚しおいる堎合は、起動しおから、䞋の [Deploy to Salesforce (Salesforce にリリヌス)] リンクを䜿甚しお、たず ApexMocks ラむブラリ、次に Apex Commons ラむブラリ をむンストヌルしおください。これらのラむブラリずそれぞれのオヌプン゜ヌス䜿甚蚱諟契玄に぀いおの詳现は、各リポゞトリを参照しおください。

リ゜ヌス

Salesforce ヘルプで Trailhead のフィヌドバックを共有しおください。

Trailhead に぀いおの感想をお聞かせください。[Salesforce ヘルプ] サむトから新しいフィヌドバックフォヌムにい぀でもアクセスできるようになりたした。

詳现はこちら フィヌドバックの共有に進む