Support and Documentation

Save life cycle

As editors create and modify items, Brightspot makes corresponding changes in the database. You can override callbacks to provide additional functionality during the save life cycle. For example, when Brightspot successfully saves an item, you can display a notification in the content edit form.

Understanding the save life cycle

The save life cycle starts with either of the following methods:

  • Record#save—Calling this method performs a standard save.

  • Record#saveImmediately—Calling this method saves the object outside the context of a transaction.

The following diagram shows the various callbacks you can use during this life cycle.

Save life cycle
Figure 88. Save life cycle


Referring to the previous diagram—

Note

The save life cycle incurs overhead for callbacks and validation. If you want to save data without validation, such as during a large ingestion, save objects with the Record#saveUnsafely method.

Save life cycle callbacks

This section describes the various callbacks during the extended save life cycle. These callbacks correspond to the diagram Save life cycle.

Note

If you need to save or delete an object in the following callbacks, always use saveImmediately or deleteImmediately. If you need to save or delete multiple objects, consider using a database transaction (see Transactions) with Database#beginIsolatedWrites.

beforeSave

Use beforeSave for simple state changes and low-overhead database or API calls. In particular, you can use this method to modify data before the validation step in the save life cycle. One common use for beforeSave is to populate hidden fields. Because editors cannot directly populated these fields in the UI, you must populate them in code.

import com.psddev.cms.db.Content;
import com.psddev.cms.db.ToolUi;

public class Article extends Content {

    private String name;

    private String code;

    /* Declare a hidden field. */
    @ToolUi.Hidden
    private String internalName;

    public String getName() {
        return name;
    }

    public String getCode() {
        return code;
    }

    /* Populate a hidden field. */
    @Override
    public void beforeSave() {
        this.internalName = getName() + "-" + getCode();
    }
}
onValidate

Use onValidate for custom validation on an object beyond what the database or annotations supply, such as sending customized messages to the UI.

In the following snippet, the name field is annotated with @Recordable.Required. If an editor saves an item with a blank name, Brightspot displays a standard error message. The snippet overrides the onValidate callback to display a custom error message.

import com.psddev.cms.db.Content;

public class Article extends Content {

    @Required
    private String name;

    /* Display custom error message. */
    protected void onValidate() {
        if (name == null) {
            getState().addError(getState().getField("name"), "Enter a name.");
        }
    }
}
Table 27. Error messages for an empty required field
Standard error message
Figure 89. Standard error message


Custom error message
Figure 90. Custom error message




beforeCommit

Use beforeCommit to make additional changes to the object that do not require validation. Examples include ensuring certain fields are null, prepending or appending strings, or populating fields with valid non-null values.

In the following example, the beforeSave method sets the lastUpdated field to the current date and time.

import com.psddev.cms.db.Content;
import com.psddev.cms.db.ToolUi;

public class Article extends Content {

    @ToolUi.Hidden
    private Date lastUpdated;

    protected void beforeCommit() {
        lastUpdated = new Date();
    }
}
onDuplicate

Use onDuplicate or provide custom logic when the database save operation fails because a uniqueness violation is detected on an indexed field or method. The most common uses of this method are the following:

  • Resolve the violation by setting a unique value and return true. In this case the save life cycle returns to the onValidate method.

  • Display a custom message in the content edit form and return false. In this case the save life cycle returns to the beforeSave method.

In the following example, the headline field is annotated with @Indexed(unique = true). If an editor saves an item with an existing headline, Brightspot displays a standard error message. The following snippet overrides the onDuplicate callback to display a custom error message.

import com.psddev.cms.db.Content;
import com.psddev.dari.db.ObjectIndex;

public class Article extends Content {

    @Indexed(unique = true)
    private String headline;

    /* Display custom error message. */
    protected boolean onDuplicate(ObjectIndex index) {
        getState().addError(getState().getField("headline"), "Another article has this headline. Use a different headline.");
        return false;
    }

}
Table 28. Error messages for duplicate values
Standard error message
Figure 91. Standard error message


Custom error message
Figure 92. Custom error message




afterSave

Use afterSave to provide processing after the database save, typically for sending messages to the UI or to log files. The following snippet overrides the afterSave callback to write a message to stdout.

import com.psddev.cms.db.Content;

public class Article extends Content {

    private String headline;

    public String getHeadline() {
        return headline;
    }

    /* Write message to stdout. */
    protected void afterSave() {
        System.out.println("Saved an article with the following headline: " + getHeadline());
    }

}
27-Feb-2020 14:32:06 INFO Saved an article with the following headline: After 300 years, Astronaut Higgins escapes from black hole. Doesn't look a day older.