Technical Blog

2 Posts tagged with the value tag

Elastic Path comes with a very flexible attribute system, allowing you to customize the attributes associated with products, skus, customers, categories, and more. Attributes can be expressed as several different types -- strings, lists of strings, integers, decimals, booleans, images, etc. -- so that a great variety of information can be associated with your domain objects.

 

Editing this information is fairly straightforward in the Commerce Manager client. However, if you'd like to restrict an attribute to certain values, there is currently no way to enforce this in the client, and the potential exists for entering data incorrectly. This can cause problems if you are relying on the value of a particular attribute for functionality on your website, or perhaps for interfacing with your back-end systems.

 

Fortunately, we have the EP source code and can implement this functionality with a little effort, using a list of options stored in the database and some modifications to the Commerce Manager Client.

 

Domain Objects

 

Attribute values are derived from com.elasticpath.domain.attribute.impl.AbstractAttributeValueImpl, which is a "mapped superclass", meaning that there is no superclass db table and subclasses exist separately in their own db table. Since we need to maintain a per-attribute list of legal attribute values, we can simply leverage this existing infrastructure:

 

@Entity
@Table(name = AttributeOptionImpl.TABLE_NAME)
public class AttributeOptionImpl extends AbstractAttributeValueImpl {
 
     /**
      * The name of the table & generator to use for persistence.
      */
     public static final String TABLE_NAME = "TATTRIBUTEOPTION";
     
     private long uidPk;
 
     /**
      * Gets the unique identifier for this domain model object.
      *
      * @return the unique identifier.
      */
     @Id
     @Column(name = "UIDPK")
     @GeneratedValue(strategy = GenerationType.TABLE, generator = TABLE_NAME)
     @TableGenerator(name = TABLE_NAME, table = "JPA_GENERATED_KEYS", pkColumnName = "ID", valueColumnName = "LAST_VALUE", pkColumnValue = TABLE_NAME)
     public long getUidPk() {
          return uidPk;
     }
 
     /**
      * Sets the unique identifier for this domain model object.
      *
      * @param uidPk the new unique identifier.
      */
     public void setUidPk(final long uidPk) {
          this.uidPk = uidPk;
     }
}

 

Because the superclass already defines the link to the Attribute as well as the fields for storing the actual value, there is nothing more to define in the subclass. Don't forget to create TATTRIBUTEOPTION and add an entry to JPA_GENERATED_KEYS!

 

These attribute value options will belong to the Attribute entity, so we will need a "join" in com.elasticpath.domain.attribute.impl.AttributeImpl (or a subclass to minimize EP code changes):

 

     private List<AttributeValue> attributeOptions;
 
 
     @OneToMany(targetEntity = AttributeOptionImpl.class,
                  cascade = { CascadeType.ALL })
     @ElementJoinColumn(name = "ATTRIBUTE_UID", nullable = false)
     @ElementDependent
     @ElementForeignKey
     public List<AttributeValue> getAttributeOptions() {
          return this.attributeOptions;
     }
     
     public void setAttributeOptions(final List<AttributeValue> attributeOptions) {
          this.attributeOptions = attributeOptions;
     }

 

These methods will need to be exposed via the Attribute interface as well. You will also need to modify the fetch groups you are using when retrieving attributes, either by adding attribute options to the 'attributes' fetch group, or for better performance as a separate fetch group that is included as needed in the CM Client (such as in CM Client's ProductEditorInput.retrieveProduct()).

 

User Interface

 

Now that the domain objects have been defined, we can turn our attention towards the user interface. Because the attributes were built with extensibility in mind, editing attributes has been somewhat modularized, making it easier for us to plug in our attribute option selection where appropriate.

 

Dialog for Selecting Among Options

 

The first thing we'll do is create a simple dialog for choosing among our attribute options (I've left out some boilerplate such as setting the title):

public class AttributeOptionDialog extends AbstractEpDialog implements IValueRetriever {
     /**
      * the attribute being edited.
      */
     private Attribute attr;
 
 
     /**
      * the value of the handled attribute.
      */
     private Object value;
 
     private CCombo comboBox;
     
     private List<AttributeValueWithType> comboValues;
     
     /**
      * The constructor of the attribute option dialog window.
      * 
      * @param parentShell the parent shell object of the dialog window
      * @param value the attribute value passed in
      */
     public AttributeOptionDialog(final Shell parentShell, final Object value, Attribute attr) {
          super(parentShell, 2, false);
          this.value = value;
          this.attr = attr;
     }
 
     /**
      * Create the set and cancel button on the dialog window.
      * 
      * @param buttonsBarType The button bar type object passed in.
      * @param parent the parent composite
      */
     @Override
     protected void createEpButtonsForButtonsBar(final ButtonsBarType buttonsBarType, final Composite parent) {
          createEpOkButton(parent, CoreMessages.AbstractEpDialog_ButtonOK, null);
          createEpCancelButton(parent);
     }
 
     /**
      * Create the content of integer dialog window.
      * 
      * @param dialogComposite The dialog composite object
      */
     @Override
     protected void createEpDialogContent(final IEpLayoutComposite dialogComposite) {
          this.comboBox = dialogComposite.addComboBox(EpState.EDITABLE, dialogComposite.createLayoutData(IEpLayoutData.FILL,
                    IEpLayoutData.CENTER, true, true));
          this.comboBox.setVisibleItemCount(20);
     }
 
     /**
      * Handle button pressed event.
      */
     @Override
     protected void okPressed() {
          if (comboBox.getSelectionIndex() >= 0 && comboBox.getSelectionIndex() < comboValues.size()) {
               this.value = comboValues.get(comboBox.getSelectionIndex()).getValue();
          }
          super.okPressed();
     }
 
     /**
      * Get the input value.
      * @return the value input by the user.
      */
     public Object getValue() {
          return this.value;
     }
 
     /**
      * populate the control created in the dialog window.
      */
     @Override
     protected void populateControls() {
          if (attr.getAttributeOptions() != null ) {
               comboValues = new ArrayList<AttributeValueWithType>();
               for( AttributeValue option : attr.getAttributeOptions()) {
                    comboValues.add((AttributeValueWithType)option);
               }
               
               Collections.sort(comboValues);
 
               if (value != null) {
                    int index = 0;
                    for(AttributeValueWithType option : comboValues) {
                         comboBox.add(option.getStringValue());
                         if (value.equals(option.getValue())) {
                              comboBox.select(index);
                         }
 
                         index++;
                    }
               } else {
                    for(AttributeValueWithType option : comboValues) {
                         comboBox.add(option.getStringValue());
                    }
               }
          }
     }
}

 

This dialog will present the user with a drop down list containing the attribute options, sorted according to their natural ordering. When OK is pressed, the dialog's value will be set to the selected attribute value.

 

Now we need to modify the attribute editing code in com.elasticpath.cmclient.catalog.editors.attribute, which is utilized throughout the CM Client UI. In AttributeEditingSupport.java we'll find the code for managing the dialogs and cell editors used for editing attributes.

 

There are two paths a user can take for editing an attribute's value: a user can select the attribute and press the edit button, which presents a dialog, or click in the table cell, which leads to the same dialog in most cases, but is directly editable in the case of short text values. For simplicity's sake we will present our dialog when the user takes either of the two actions (another approach, for a more seamless UI, might be to switch to a ComboBoxEditor to place a dropdown menu directly in the cell). One final exception to worry about is multi-valued short text values -- we will display a modified version of the ShortTextMultiValueDialog.

 

Most of the cell editors use a DialogCellEditor for editing their contents. We will add a check to see if the attribute has AttributeOptions, and open our dialog instead. To keep our EP code changes to a minimum, we will insert a new class into the hierarchy between DialogCellEditor and the individual cell editor classes, which checks for attribute options and opens our new dialog if they exist:

 

public abstract class AttributeDialogCellEditor extends DialogCellEditor {
 
     private final AttributeValue attr;
 
     protected AttributeDialogCellEditor(final Composite parent,
               final AttributeValue attr) {
          super(parent);
          this.attr = attr;
     }
 
     @Override
     protected Object openDialogBox(Control cellEditorWindow) {
          if (!attr.getAttribute().isMultiValueEnabled() &&
                    attr.getAttribute().getAttributeOptions() != null &&
                    attr.getAttribute().getAttributeOptions().size() > 0) {
               final AttributeOptionDialog dialog = new AttributeOptionDialog(cellEditorWindow.getShell(), 
                         attr.getValue(), attr.getAttribute());
               dialog.open();
               return dialog.getValue();
          }
          return onOpenDialogBox(cellEditorWindow);
     }
     
     protected abstract Object onOpenDialogBox(Control cellEditorWindow);
}

 

Then we can make three minor changes to each of the dialog cell editors in AttributeEditingSupport.java -- change the class they extend to AttributeDialogCellEditor, add 'attr' as an argument to super(), and rename the openDialogBox() method to onOpenDialogBox().

 

To finish up attribute editing, there are two other places in AttributeEditingSupport where we need to display our dialog:

 

     public static Window getEditorDialog(final AttributeValue attr, final Shell shell) {
          /* Begin new code */
          if (!attr.getAttribute().isMultiValueEnabled() &&
                         attr.getAttribute().getAttributeOptions() != null &&
                         attr.getAttribute().getAttributeOptions().size() > 0) {
               return new AttributeOptionDialog(shell, attr.getValue(), attr.getAttribute());
          }
          /* End new code */

 

And:

 

     protected CellEditor getCellEditor(final AttributeValue attr) {
          final Table table = this.attributesTableViewer.getSwtTable();
          CellEditor result = null;
          switch (attr.getAttributeType().getTypeId()) {
          case AttributeType.SHORT_TEXT_TYPE_ID:
               if (attr.getAttribute().isMultiValueEnabled()
                              /* Begin new code */
                              || (attr.getAttribute().getAttributeOptions() != null &&
                              attr.getAttribute().getAttributeOptions().size() > 0)
                              /* End new code */
                         ) {
                    result = new ShortTextCellEditor(table, attr);
                    break;
               }

 

The former change will show our dialog when the user presses the edit button, and the latter will show our dialog when a short text value's cell is clicked (which is normally directly editable).

 

For multi-valued short text values, we need to modify the addAction() and editAction() methods of the ShortTextMultiValueDialog. Attribute values will be entered using our new dialog, if the attribute has options:

 

     private void addAction() {
          String addedValue = null;
          if ( model.getAttribute().getAttributeOptions() != null &&
               model.getAttribute().getAttributeOptions().size() > 0 ) {
               final AttributeOptionDialog dialog = new AttributeOptionDialog(getShell(),
                         null, model.getAttribute());
               if ( dialog.open() != Window.OK ) {
                    return;
               }
               addedValue = (String)dialog.getValue();
               
               if (addedValue == null) {
                    return;
               }
          } else {
               final ShortTextDialog dialog = new ShortTextDialog(getShell(),
                         null, false);
               final int result = dialog.open();
               if (result != Window.OK) {
                    return;
               }
               addedValue = dialog.getValue();
          }
 
          if (addedValue == null) {
               return;
          }
 
          getShortTextValues().add(addedValue);
          setShortTextValues(getShortTextValues());
          refreshViewer();
          setValue(getModel().getStringValue());
 
     }
 
 
     private void editAction() {
          String editedValue = null;
          final String originalString = getSelectedValue();
          if ( model.getAttribute().getAttributeOptions() != null &&
               model.getAttribute().getAttributeOptions().size() > 0 ) {
               final AttributeOptionDialog dialog = new AttributeOptionDialog(getShell(),
                         originalString, model.getAttribute());
               if ( dialog.open() != Window.OK ) {
                    return;
               }
               editedValue = (String)dialog.getValue();
               
               if (editedValue == null) {
                    return;
               }
          } else {
               final ShortTextDialog dialog = new ShortTextDialog(getShell(),
                         originalString, true);
               final int result = dialog.open();
               if (result != Window.OK) {
                    return;
               }
               editedValue = dialog.getValue();
               
               if (editedValue == null) {
                    return;
               }
          }
 
          List<String> editedList = new ArrayList<String>();
          for (String element : getShortTextValues()) {
               if (element.equals(originalString)) {
                    editedList.add(editedValue);
               } else {
                    editedList.add(element);
               }
          }
 
          setShortTextValues(editedList);
 
          shortTextValueTableViewer.setInput(editedList.toArray());
          shortTextValueTableViewer.getSwtTableViewer().refresh();
          setValue(getModel().getStringValue());
 
     }
 

 

Creating the Options

 

Finally, the administrator needs to input the list of options for each particular attribute. We will make the necessary changes in a subclass of com.elasticpath.cmclient.catalog.dialogs.catalog.CatalogAttributesAddEditDialog:

 

public class AttributeOptionCatalogAttributesAddEditDialog extends CatalogAttributesAddEditDialog 
     implements SelectionListener, ISelectionChangedListener {
     private IEpTableViewer attributesTableViewer;
 
     private Button removeButton;
 
     private Button addButton;
 
     public CatalogAttributesWithOptionsDialog(final Shell parentShell,
          final Attribute attribute, final boolean isGlobal) {
          super(parentShell, attribute, isGlobal);
     }

 

To createEpDialogContent(), we will add a table to display the options:

     protected void createEpDialogContent(
               final IEpLayoutComposite dialogComposite) {
          super.createEpDialogContent(dialogComposite);
          
          final IEpLayoutData labelData = dialogComposite.createLayoutData(
                    IEpLayoutData.END, IEpLayoutData.FILL);
          final IEpLayoutData fieldData = dialogComposite.createLayoutData(
                    IEpLayoutData.FILL, IEpLayoutData.FILL, true, false);
 
          dialogComposite.addLabelBold(
                    "Restrict values to", //$NON-NLS-1$
                    labelData);
 
          dialogComposite.addLabel(
                    "", //$NON-NLS-1$
                    fieldData);
          
          IEpLayoutComposite allowedValuesComposite = dialogComposite.addGridLayoutComposite(2, false, 
                    dialogComposite.createLayoutData(IEpLayoutData.FILL, IEpLayoutData.FILL, true, false, 2, 1));
          attributesTableViewer = allowedValuesComposite.addTableViewer(false,
                    EpState.EDITABLE, 
                    allowedValuesComposite.createLayoutData(IEpLayoutData.END, IEpLayoutData.FILL, false, true));
          
          attributesTableViewer.addTableColumn( "Value", //$NON-NLS-1$
                    400).setLabelProvider(new ColumnLabelProvider() {
               public String getText(final Object element) {
                    final AttributeValue value = (AttributeValue) element;
                    return value.getStringValue();
               }
          });
          
          attributesTableViewer.setContentProvider(new IStructuredContentProvider() {
               public Object[] getElements(final Object inputElement) {
                    Attribute attributeInput = (Attribute)inputElement;
                    if (attributeInput.getAttributeOptions() != null) {
                         List<AttributeValueWithType> attributeOptions = new ArrayList<AttributeValueWithType>();
                         for( AttributeValue av : attributeInput.getAttributeOptions() ) {
                              attributeOptions.add((AttributeValueWithType)av);
                         }
                         Collections.sort(attributeOptions);
                         return attributeOptions.toArray();
                    }
                    return new Object [0];
               }
               public void dispose() {}
               public void inputChanged(Viewer arg0, Object arg1, Object arg2) {}
          });
          
          IEpLayoutComposite buttonsComposite = allowedValuesComposite.addGridLayoutComposite(1, false, null);
 
          // create add button
          final Image addImage = CoreImageRegistry
                    .getImage(CoreImageRegistry.IMAGE_ADD);
          addButton = buttonsComposite.addPushButton(
                    "Add value", addImage, //$NON-NLS-1$
                    EpState.EDITABLE, buttonsComposite.createLayoutData(
                              IEpLayoutData.FILL, IEpLayoutData.BEGINNING));
          addButton.addSelectionListener(this);
          
          // create remove button
          final Image removeImage = CoreImageRegistry
                    .getImage(CoreImageRegistry.IMAGE_REMOVE);
          removeButton = buttonsComposite.addPushButton(
                    "Remove value", removeImage, //$NON-NLS-1$
                    EpState.EDITABLE, buttonsComposite.createLayoutData(
                              IEpLayoutData.FILL, IEpLayoutData.BEGINNING));
          removeButton.addSelectionListener(this);
 
          attributesTableViewer.getSwtTableViewer().addSelectionChangedListener(this);
     }

 

We will initialize our new controls in populateControls():

     public void populateControls() {
          super.populateControls();
          
          addButton.setEnabled(true);
          removeButton.setEnabled(true);
          attributesTableViewer.setInput(getAttribute());
     }
     

 

And (finally!), we can handle the add/remove functionality, leveraging the existing attribute editing dialogs for entering our values:

 

     public void widgetDefaultSelected(SelectionEvent arg0) {
          // not used
     }
     
     private AttributeValue getSelectedValue() {
          return (AttributeValue) ((IStructuredSelection) attributesTableViewer.getSwtTableViewer()
                    .getSelection()).getFirstElement();
     }
 
     public void widgetSelected(SelectionEvent event) {
 
          if ( event.getSource() == addButton) {
               addValue();
          } else if ( event.getSource() == removeButton) {
               final AttributeValue attribute = getSelectedValue();
               if ( attribute != null ) {
                    removeValue(attribute);
               }
          }
          
     }
     
     private void addValue() {
          AttributeValue newOpt = Application.getInstance().getElasticPath().getBean(ContextIdNames.ATTRIBUTE_OPTION);
          newOpt.setAttribute(attribute);
          newOpt.setLocalizedAttributeKey(attribute.getKey());
          newOpt.setAttributeType(attribute.getAttributeType());
          Window dialog = getEditorDialog(newOpt, getShell());
          if ( dialog.open() == Window.OK ) {
               final IValueRetriever retriever = (IValueRetriever) dialog;
               if ( retriever.getValue() != null ) {
                    newOpt.setValue(retriever.getValue());
                    List<AttributeValue> attributeOptions = attribute.getAttributeOptions();
                    if ( attributeOptions == null ) {
                         attributeOptions = new ArrayList<AttributeValue>();
                    }
                    attributeOptions.add(newOpt);
                    attribute.setAttributeOptions(attributeOptions);
                    attributesTableViewer.getSwtTableViewer().refresh();
               }
          }
     }
     
     private void removeValue(AttributeValue attr) {
          List<AttributeValue> attributeOptions = attribute.getAttributeOptions();
          if ( attributeOptions != null ) {
               for( int index = 0; index < attributeOptions.size(); index++ ) {
                    if ( attributeOptions.get(index).getUidPk() == attr.getUidPk() ) {
                         attributeOptions.remove(index);
                         attribute.setAttributeOptions(attributeOptions);
                         attributesTableViewer.getSwtTableViewer().refresh();
                         break;
                    }
               }
          }
     }
 
     public void selectionChanged(SelectionChangedEvent event) {
          //not used
     }
     
     private Window getEditorDialog(final AttributeValue attr, final Shell shell) {
 
          Window dialog = null;
          switch (attr.getAttributeType().getTypeId()) {
          case AttributeType.BOOLEAN_TYPE_ID:
               dialog = new BooleanDialog(shell, attr.getValue());
               break;
          case AttributeType.DATE_TYPE_ID:
               dialog = new DateTimeDialog(shell, attr.getValue(),
                         IEpDateTimePicker.STYLE_DATE);
               break;
          case AttributeType.DATETIME_TYPE_ID:
               dialog = new DateTimeDialog(shell, attr.getValue(),
                         IEpDateTimePicker.STYLE_DATE
                                   | IEpDateTimePicker.STYLE_DATE_AND_TIME);
               break;
          case AttributeType.DECIMAL_TYPE_ID:
               dialog = new DecimalDialog(shell, attr.getValue());
               break;
          case AttributeType.INTEGER_TYPE_ID:
               dialog = new IntegerDialog(shell, attr.getValue());
               break;
          case AttributeType.LONG_TEXT_TYPE_ID:
               dialog = new LongTextDialog(shell, attr.getValue());
               break;
          case AttributeType.SHORT_TEXT_TYPE_ID:
               dialog = new ShortTextDialog(shell, attr.getValue(), true);
               break;
          case AttributeType.IMAGE_TYPE_ID:               
               dialog = AssetManager.createAssetManagerImagesDialog(shell);
               break;
          case AttributeType.FILE_TYPE_ID:               
               dialog = AssetManager.createAssetManagerFilesDialog(shell);
               break;
          default:
               // throw new RuntimeException("Unknown attribute type");
          }
          return dialog;
     }

 

Lastly we just replace all references of CatalogAttributesAddEditDialog with our new AttributeOptionCatalogAttributesAddEditDialog, and we're done! While not a trivial change, the existing infrastructure certainly made our job easier. Now we can restrict attributes to particular values if we need to, and not have to worry about mistypings or misspellings.

 

David Minor works for women's sportswear retailer Team Estrogen, an Elastic Path customer.

1 Comments Permalink

Elastic Path 6.1 provides a new way to manage your application configuration. In the past, settings were stored in a variety of places throughout the system; some were in XML files, others were in properties files, and still others were stored in different tables in the database. Now, the most commonly used settings are stored in the database and can be configured using the Commerce Manager.

Custom settings can be migrated to use this framework with little code change and would be able to take advantage of Elastic Path 6.1 multi-store setting management features.

Setting Definitions

Setting definitions are stored in the database, in the TSETTINGDEFINITION table. A setting definition contains:

 

  • a path
  • a default value
  • a value type
  • the maximum number of overrides

 

The path is a unique identifier for the setting. For example COMMERCE/STORE/giftcertificatesEnabled path refers to the setting that sets whether gift certificates are enabled for a given store.

The default value is the fallback to use when a specific value hasn't been assigned to the setting.

 

The value type indicates the type of value stored in the setting (a string, a number, a URL, etc.).

 

The maximum number of overrides specifies the number of values that can be assigned to a setting. Some settings can have multiple values assigned to them. Others can only have one. For example, a store-specific setting would need to have different values for different stores, so the number of overrides would be very large or unlimited (-1). For a system-wide setting, there is generally only one override.

Setting Values

The TSETTINGVALUE table contains the values that have been assigned to settings. Each value has a context. For system settings, the context is empty. For store-specific values, the context contains a store code.

Setting Metadata

Setting metadata is stored in the TSETTINGMETADATA table. It can be used to store additional configuration information relating to the setting. A setting can have any number of metadata associated with it.

Setting metadata consists of a set of key/value pairs. In Elastic Path 6.1, there are two metadata key/value pairs that can be assigned to settings:

 

  • RefreshStrategy, which defines the setting's refresh strategy

 

  • availableToMarketing, which indicates whether the setting is displayed in the store Marketing tab.

 

Setting Refresh Strategies

The setting refresh strategies metadata provides fine-grained control over when setting changes are applied to the system. In the past, most setting changes required restarting the server. Now, when the setting change is applied depends on how you've configured its refresh strategy. Out of the box, Elastic Path 6.1 provides four refresh strategies:

 

  • application: settings that use the application refresh strategy are only applied after the application is restarted

 

  • session: settings that use the session refresh strategy do not change during the lifetime of the user's session. If an administrator changes the setting value, users will not see the change until their session cookie is removed or expires and a new session is created

 

  • interval: settings that use the interval refresh strategy are cached for a specified period of time. Users do not see changes until the cache expires

 

  • immediate: settings that use the immediate refresh strategy are updated immediately. As soon as the administrator changes a setting that uses this strategy, the change is applied everywhere

Creating a Setting Definition

New setting definitions can be added by executing SQL insert statements. For example, the following creates a definition identified by the path CUSTOM/WIDGETS/widgetType:

INSERT INTO TSETTINGDEFINITION(UIDPK, PATH, DEFAULT_VALUE, VALUE_TYPE, MAX_OVERRIDE_VALUES)
VALUES(10001, "CUSTOM/WIDGETS/widgetType", "flat", "String", 0, 1);

 

For your custom settings, you should use a naming convention, to avoid conflicts with other settings. Do not use the COMMERCE path prefix, which is reserved for Elastic Path settings.

Adding a Value for the Setting

Setting values can be added by using the Commerce Manager client application. For more information, see the Commerce Manager User Manual.

You can also use SQL insert statements. Remember that you don't need to create a setting value if there is a default value that comes from the setting definition.

Assuming you do want to override the setting definition for a specific context (store code for stores), you can create the value with the following SQL:

INSERT INTO TSETTINGVALUE(UIDPK, SETTING_DEFINITION_UID, CONTEXT, CONTEXT_VALUE)
 VALUES(1011, 10001, "SLRWORLD", "circle")

 

Note the value of SETTING_DEFINITION_UID should match the UIDPK for the related row in TSETTINGDEFINITION.

Note that multiple setting values can be defined on a setting definition if the setting definition's max_override_values field is set to -1.

 

Settings Framework Services

Elastic Path 6.1 provides a low level SettingsService class to manage and retrieve of setting definitions and values. To get a setting value for a system level setting with no context:

SettingsService settingsService = getElasticPath()
   getBean(ContextIdNames.SETTINGS_SERVICE);
final int numOfMinutes = Integer.valueOf(settingsService.getSettingValue(
   "COMMERCE/APPSPECIFIC/RCP/idleTimeForLock").getValue());

 

To get a setting value for a particular context:

settingsService.getSettingValue(path, store.getCode()).getValue();

 

If there is no setting value in TSETTINGVALUE for the specified context, the system will fall back to the default value in TSETTINGDEFINITION. For example, the default value of the COMMERCE/STORE/giftcertificatesEnabled setting is false, but a setting value for the context SNAPITUP is true, so the Snap It Up store has gift certificates enabled.

 

A SettingsReader service interface is provided for read only operations. Additionally, the CachedSettingsReader service wrapper provides caching for settings retrieval, and is the preferred method in the storefront to avoid frequent database calls.

 

In storefront controllers, the StoreConfig object (available through the RequestHelper) can be used to obtain setting values. If a store specific value is available, it will automatically be retrieved. Otherwise, the default value from the setting definition is returned.  For example:

String pagination = getRequestHelper().getStoreConfig()
 getSetting("COMMERCE/STORE/CATALOG/catalogViewPagination").getValue();
int paginationNumber = NumberUtils.toInt(pagination, DEFAULT_PAGINATION);

 

Elastic Path 6.1's settings framework should replace usage of configuration files for custom configuration settings, especially where multiple stores are being deployed. Previous code retrieving settings from the ElasticPathImpl object should be migrated to the settings framework and its suite of APIs.

0 Comments 0 References Permalink