Saturday, June 21, 2025

Understanding WITH SECURITY_ENFORCED in Salesforce Apex

When writing Apex code in Salesforce, it’s important to protect data by checking user permissions like Field-Level Security (FLS) and Object-Level Security (OLS). One way to do this is by using WITH SECURITY_ENFORCED in your SOQL queries.

This keyword tells Salesforce to check if the current user has access to the fields and objects in the query. If the user doesn’t have access, the query fails and throws an error. This helps avoid showing data that the user shouldn’t see.

Account[] accts = [SELECT Name, AnnualRevenue FROM Account WITH SECURITY_ENFORCED];

In this example, Salesforce checks if the user can access the Name and AnnualRevenue fields. If not, it will stop the query and show an error.

Salesforce Recommendation: Use USER_MODE Instead

Salesforce recommends using WITH USER_MODE instead of WITH SECURITY_ENFORCED because it has fewer limitations and works better in more situations.

With USER_MODE, your Apex code runs as if it were the user, automatically respecting all their permissions—without needing extra checks.

For more details on user mode please refer blog https://www.sfdc-lightning.com/2025/06/user-mode-in-apex-new-way-to-respect.html

Important Notes:

Don’t use WITH SECURITY_ENFORCED and USER_MODE together in the same query.

If you switch to USER_MODE, remove any WITH SECURITY_ENFORCED clauses—they’re not needed.

Using both together will cause errors.

Limitations of WITH SECURITY_ENFORCED:

  • Works only with SOQL

WITH SECURITY_ENFORCED works only in SOQL queries. It cannot be used with SOSL or DML.

Valid Example:

Account[] accs = [SELECT Name FROM Account WITH SECURITY_ENFORCED];

  • Does not support relationship fields

You cannot use relationship fields like Owner.Name in the query.

Invalid Example:

[SELECT Name, Owner.Name FROM Account WITH SECURITY_ENFORCED];

  • Cannot be used in dynamic SOQL

WITH SECURITY_ENFORCED does not work in queries written as strings and executed at runtime.

Invalid Example:

String soql = 'SELECT Name FROM Account WITH SECURITY_ENFORCED';

Database.query(soql); // This will fail

  • Exceptions cannot be caught

If the user doesn’t have access to a field or object, the query throws an exception that cannot be handled with try-catch.

Invalid Example:

try {

    [SELECT Name, AnnualRevenue FROM Account WITH SECURITY_ENFORCED];

} catch (Exception e) {

    // This will not catch the error

}

  • No partial access allowed

If the user lacks access to even one field, the entire query fails. It does not return partial results.

Example:

[SELECT Name, AnnualRevenue FROM Account WITH SECURITY_ENFORCED];

Friday, June 20, 2025

User Mode in Apex – The New Way to Respect Permissions

 In Salesforce, Apex code runs in system mode by default. That means it can access all data, even if the current user doesn’t have permission. This can lead to security issues if you're not careful.

To fix this, Salesforce introduced User Mode – a cleaner and safer way to run SOQL and DML operations as the user.

What is User Mode?

User Mode lets your code automatically respect:

  • Field-level security (FLS)
  • Object-level security (CRUD)

This means your queries and operations behave just like the user is running them.

How to Use User Mode

You can use User Mode in these operations:

Database.query(new Query("SELECT Name FROM Account").setUserMode(UserMode.CURRENT));


Database.getQueryLocator(new Query("SELECT Name FROM Account").setUserMode(UserMode.CURRENT));

You can also use it with:

  • Database.countQuery()
  • Database.insert(), update(), delete() – by setting user mode through Database.DMLOptions


Benefits

  • No need to manually check FLS or CRUD
  • Prevents accidental access to restricted data
  • Works across async processes and batch jobs
  • Safer and more user-friendly than WITH SECURITY_ENFORCED

Why It Matters

User Mode is the recommended approach by Salesforce. It makes your Apex code more secure, easier to maintain, and aligned with user permissions—automatically.

Here are real-life examples of using User Mode in Apex code to make sure your logic respects user permissions (FLS & CRUD):

Example 1: Querying Accounts Securely in a Controller

Without User Mode (runs in system mode – not secure):

List<Account> accounts = [SELECT Id, Name, Industry FROM Account];


With User Mode (recommended):

Query query = new Query('SELECT Id, Name, Industry FROM Account')

    .setUserMode(UserMode.CURRENT);


List<Account> accounts = Database.query(query);


Now the query will return only fields the current user is allowed to access.

Example 2: Batch Apex – Get Records with Respect to User Access

Batch class using User Mode in start method:

global class AccountBatch implements Database.Batchable<SObject> {

    global Database.QueryLocator start(Database.BatchableContext BC) {

        Query query = new Query('SELECT Id, Name FROM Account')

            .setUserMode(UserMode.CURRENT);

        return Database.getQueryLocator(query);

    }


    global void execute(Database.BatchableContext BC, List<SObject> scope) {

        // Process records here

    }


    global void finish(Database.BatchableContext BC) {}

}


Example 3: Secure DML Operation (Insert)

Without User Mode (may insert data user isn't allowed to):

insert new Account(Name='Test');

With User Mode:

Account acct = new Account(Name='Test');


Database.DMLOptions dmlOpts = new Database.DMLOptions();

dmlOpts.setUserMode(UserMode.CURRENT);


Database.insert(acct, dmlOpts);


If the user doesn’t have create access to the Account object, this insert will fail safely.

Example 4: Reporting Component – Avoid Showing Restricted Fields

Say you’re building a custom report viewer in LWC or Aura and calling Apex:

Query query = new Query('SELECT Name, AnnualRevenue, Industry FROM Account')

    .setUserMode(UserMode.CURRENT);


List<Account> result = Database.query(query);


If the user can't see AnnualRevenue, it will automatically be excluded from results — no error, no extra code!

Sunday, June 8, 2025

Exploring Lifecycle Flow in LWC with Getters, Setters, and DOM Events

 To demonstrate the lifecycle hooks flow in Lightning Web Components (LWC) in sequence, we can create a component that logs the execution of each lifecycle hook. I'll also use getters, setters, the constructor, connected callback, render and rendered callback for this demonstration. Here's how you can implement this:

Explanation:

• Constructor: Called first when the component is created. It’s useful for initializing values.
• Getter/Setter: The fetchName property has both a getter and a setter, which log when the property is accessed or modified.
• connectedCallback: Called when the component is inserted into the DOM. It is a good place to initialize data or make external calls.
• disconnectedCallback: Called when the component is removed from the DOM. It's typically used for cleanup operations.
• render: Called before the component is rendered to the DOM, which is useful for modifying the DOM before the component is visually updated.
• renderedCallback: Called after the component is rendered to the DOM. It is useful for performing any tasks that need to occur after the DOM is updated.

 

More about Getters and Setters:

Getters:

getter is like a way to get or read the value of a property. Whenever you try to access a property, the getter is automatically called. Think of a getter like opening a box to look at what's inside. You can’t change the contents of the box directly through a getter — it only lets you see the current value.

• Example: If you want to know what the current value of a fetchName is, you can use the getter. The getter will return the current value stored inside the property.

Setters:

setter is like a guardian for a property. It allows you to set or update the value of the property. Whenever you assign a new value to a property, the setter is triggered. Setters make sure that the value you’re trying to assign is allowed, and can even adjust it before it's saved. You can think of a setter as a person who checks the box and only lets in the values that meet certain rules.

• Example: If you want to change the fetchName value, the setter will be used to update it. It may also check if the new value is valid.

 

 

Template File:

<template>

    <h1>{fetchName}</h1>

    <button onclick={handleChangeName}>Change Name</button>

</template>

 

Javascript File:

import { LightningElement } from 'lwc';

 

export default class LifecycleHooksDemo extends LightningElement {

    // Property with getter and setter

    fullName = 'LWC Lifecycle';

 

    get fetchName() {

        console.log('Getter: name is being accessed');

        return this.fullName;

    }

 

    // Setter for the name property

    set fetchName(value) {

        console.log('Setter: name is being set to', value);

        this.fullName = value;

    }

 

    

    handleChangeName() {

        this.fetchName = 'New Name';

    }

    

    // Constructor (executed when the component is created)

    constructor() {

        super();

        console.log('Constructor: Component is created');

    }

 

    // connectedCallback (executed when the component is inserted into the DOM)

    connectedCallback() {

        console.log('connectedCallback: Component is inserted into the DOM');

    }

 

    // disconnectedCallback (executed when the component is removed from the DOM)

    disconnectedCallback() {

        console.log('disconnectedCallback: Component is removed from the DOM');

    }

 

    // render (executed before the component is rendered to the DOM)

    render() {

        console.log('render: Component is about to render');

        return super.render();

    }

 

    // renderedCallback (executed after the component is rendered to the DOM)

    renderedCallback() {

        console.log('renderedCallback: Component has been rendered');

    }

 

}

 

When component is previewed:

When we click Change Name button:

Monday, June 2, 2025

Understanding the Difference Between @wire Properties and @wire Functions in LWC

Understanding the Difference Between @wire Properties and @wire Functions in LWC

When working with Lightning Web Components (LWC), the @wire decorator is used to read data reactively. However, there's often confusion between using it with properties versus functions.

Let’s simplify and clarify the distinction.

@wire with a Property — Simplicity and Reactivity

What it means:

Using @wire with a property is like telling Salesforce:

"Fetch the data and assign it automatically. I don't want to manage the logic."

Key Features:

You get a reactive object with .data and .error keys.

Salesforce manages the invocation based on reactive parameters.

Best for simple data display with minimal logic.

Syntax:

js

@wire(fetchContacts) contacts;

Usage in Template:

html

<template if:true={contacts.data}>

  <template for:each={contacts.data} for:item="contact">

    <p key={contact.Id}>{contact.Name}</p>

  </template>

</template>

Ideal When:

You just need to render data as-is.

You don't need complex logic or transformation.

Error handling isn’t critical or is handled elsewhere.

@wire with a Function — Control and Customization

What it means:

Using @wire with a function tells Salesforce:

"Give me the data, and I’ll decide what to do with it."

Key Features:

You receive data and error as arguments.

You control how to handle and manipulate the response.

Great for custom processing, filtering, or dynamic UI logic.

Syntax:

js

@wire(fetchContacts)

handleContacts({ data, error }) {

  if (data) {

    // Example: Only include contacts with email addresses

    this.filteredContacts = data.filter(c => c.Email);

  } else if (error) {

    this.showErrorNotification(error);

  }

}

Ideal When:

You need to filter, sort, or transform data.

Error handling must vary based on context.

You need conditional assignments or advanced logic.

Real-World Example Comparison:

Scenario: You want to display a list of contacts — only those with a phone number.

Using a Wire Property (not ideal here):

js

@wire(fetchContacts) contacts;

In the template, you’d have to manually check each one not efficient.

Using a Wire Function (better control):

js

@wire(fetchContacts)

processContacts({ data, error }) {

  if (data) {

    this.contactsWithPhone = data.filter(c => c.Phone);

  } else if (error) {

    this.notifyUser(error.message);

  }

}

Pro Tip:

Use @wire property when your component just needs to show data without much logic.

Use @wire function when you need custom behavior, data transformation, or enhanced error handling.

Sunday, May 25, 2025

No More Null Crashes! 5 Simple Apex Tips to Make Your Code Safer

Tired of late-night debugging sessions because of annoying null errors in Apex? We’ve all been there. These simple checks will help you handle lists, sets, maps, and objects with confidence — and fewer crashes.


1. != null“Does it even exist?”

This is your first safety net. Before you interact with any variable — object, list, set, or map — check if it's not null.

When to use: Always. This is your go-to check to prevent null reference exceptions.

Example:


Lead leadRecord = [SELECT Id, Email FROM Lead LIMIT 1];

if (leadRecord != null) {

    System.debug('Lead record exists!');

}

Note: This confirms the variable is present, but not whether it contains useful data.


2. !isEmpty()“Is there anything inside?”

A quick and clean way to see if your list or set has at least one item.

When to use: Ideal for lists and sets where you're only interested in whether there's data, not how much.

Example:


List<Case> openCases = [SELECT Id FROM Case WHERE Status = 'Open'];

if (!openCases.isEmpty()) {

    System.debug('There are open cases!');

}

Why it's better: It's more readable than writing size() > 0.


3. size() > 0“How many items are there?”

This tells you the number of elements in a list, set, or map — and whether it's empty or not.

When to use: Useful when you’re working with maps, or need the actual count.

Example:


Map<Id, Product2> productMap = new Map<Id, Product2>(

    [SELECT Id, Name FROM Product2 WHERE IsActive = TRUE]

);

if (productMap.size() > 0) {

    System.debug('Found ' + productMap.size() + ' active products.');

}


4. contains()“Is this item in there?”

Perfect for checking if a list or set contains a specific item.

When to use: Great for filtering or conditionally running logic.

Example:


Set<String> approvedStatuses = new Set<String>{'Approved', 'Validated'};

String currentStatus = 'Approved';


if (approvedStatuses.contains(currentStatus)) {

    System.debug('Status is approved.');

}


5. containsKey()“Is this key in the map?”

When working with maps, use this to verify a key exists before accessing it.

When to use: Always check before using map.get() to avoid surprises.

Example:


Map<Id, User> userMap = new Map<Id, User>(

    [SELECT Id, Name FROM User WHERE IsActive = TRUE]

);

Id targetUserId = UserInfo.getUserId();


if (userMap.containsKey(targetUserId)) {

    System.debug('User found in map!');

}