Dynamic Properties (Dynprops)

Dynamic properties allow you to add properties to an entity (object) as a whole and conveniently use them for filtering in a list.
These properties can only be attached to an object through an additional entity, usually a category to which the object is assigned. Depending on the specified category, the object can have a different set of properties. For example, this can be an object in the real estate category and the subcategory of new buildings.

To ensure the proper functioning of the dynamic properties component, we need tables with a specific structure. Let's consider them in detail:

Tables for dynamic properties

  1. Objects table, which will store properties common to all objects, such as the object name and creation date, as well as the connection to the category and the values ​​of the properties attached to it, fields f1-f20 (must be named exactly like this);
CREATE TABLE `bff_test_posts` (
  `id` int(11) unsigned NOT NULL AUTO_INCREMENT, -- Object ID
  `title` varchar(200) NOT NULL DEFAULT '', -- Title
  `cat_id` int(11) unsigned NOT NULL DEFAULT '0', -- Category ID
  `enabled` tinyint(1) unsigned NOT NULL DEFAULT '0',
  `content` text,
  `content_search` text,
  -- Dynamic properties values:
  `f1` float NOT NULL DEFAULT '0',
  `f2` float NOT NULL DEFAULT '0',
  `f3` float NOT NULL DEFAULT '0',
  `f4` float NOT NULL DEFAULT '0',
  `f5` float NOT NULL DEFAULT '0',
  `f6` float NOT NULL DEFAULT '0',
  `f7` float NOT NULL DEFAULT '0',
  `f8` float NOT NULL DEFAULT '0',
  `f9` float NOT NULL DEFAULT '0',
  `f10` float NOT NULL DEFAULT '0',
  `f11` float NOT NULL DEFAULT '0',
  `f12` float NOT NULL DEFAULT '0',
  `f13` float NOT NULL DEFAULT '0',
  `f14` float NOT NULL DEFAULT '0',
  `f15` float NOT NULL DEFAULT '0',
  `f16` text,
  `f17` text,
  `f18` text,
  `f19` text,
  `f20` text,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB  DEFAULT CHARSET=utf8;
  1. Categories table for the object, to which properties will be assigned:
CREATE TABLE `bff_test_cats` (
  `id` int(11) unsigned NOT NULL AUTO_INCREMENT,
  `title` varchar(200) NOT NULL DEFAULT '',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=5 DEFAULT CHARSET=utf8;
  1. Tables for storing category dynamic property settings:
CREATE TABLE `bff_test_cats_dp` (
  `id` int(11) unsigned NOT NULL AUTO_INCREMENT,
  `owner_id` int(11) unsigned NOT NULL DEFAULT '0',
  `title_ru` varchar(100) NOT NULL DEFAULT '',
  `description_ru` text,
  `type` tinyint(3) unsigned NOT NULL DEFAULT '0',
  `default_value` text,
  `req` tinyint(3) unsigned NOT NULL DEFAULT '0',
  `is_search` tinyint(3) unsigned NOT NULL DEFAULT '0',
  `is_cache` tinyint(3) unsigned NOT NULL DEFAULT '0',
  `cache_key` varchar(100) NOT NULL DEFAULT '',
  `extra` text,
  `parent` tinyint(3) unsigned NOT NULL DEFAULT '0',
  `parent_id` int(11) unsigned NOT NULL DEFAULT '0',
  `parent_value` smallint(5) unsigned NOT NULL DEFAULT '0',
  `enabled` tinyint(3) unsigned NOT NULL DEFAULT '1',
  `data_field` tinyint(3) unsigned NOT NULL DEFAULT '0',
  `num` tinyint(3) unsigned NOT NULL DEFAULT '0',
  `search_hidden` tinyint(3) unsigned NOT NULL DEFAULT '0',
  PRIMARY KEY (`id`),
  KEY `owner_id` (`owner_id`),
  CONSTRAINT `bff_test_cats_dp_ibfk_1` FOREIGN KEY (`owner_id`) REFERENCES `bff_test_cats` (`id`) ON DELETE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

-- Table for values of fields with multiple choice
CREATE TABLE `bff_test_cats_dpm` (
  `dynprop_id` int(11) unsigned NOT NULL DEFAULT '0',
  `name_ru` varchar(100) NOT NULL DEFAULT '',
  `value` int(11) NOT NULL DEFAULT '0',
  `num` tinyint(3) unsigned NOT NULL DEFAULT '0',
  KEY `dynprop_id` (`dynprop_id`),
  CONSTRAINT `bff_test_cats_dpm_ibfk_1` FOREIGN KEY (`dynprop_id`) REFERENCES `bff_test_cats_dp` (`id`) ON DELETE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

Please note the owner_id field, which points to the ID of the category for which dynamic properties are created. It will be used later in the component initialization.

Initialization of the dynamic properties component

Working with dynamic properties starts with initializing the Dynprops component new Dynprops(field_owner_id, table_categories, table_dp, table_dpm) and setting the configuration:

/**
 * Initialization of the dynamic properties component
 * @return \bff\db\Dynprops object
 */
public function dp()
{
    # save the object for subsequent method calls
    static $dp = null;
    if (isset($dp)) {
        return $dp;
    }

    # attach the "Dynamic Properties"
    $dp = $this->attachComponent(
        'dynprops',
        new \bff\db\Dynprops(
            'owner_id', # name of the owner attribute column
            'bff_test_cats', # owner attributes table, in this example, article categories
            'bff_test_cats_dp', # properties table
            'bff_test_cats_dpm' # properties values table for fields with multiple choice
        )
    );

    $dp->setSettings(array(
        'module_name'  => $this->module_name,   
        'typesAllowed' => array(
            $dp::typeCheckboxGroup,
            $dp::typeRadioGroup,
            $dp::typeRadioYesNo,
            $dp::typeCheckbox,
            $dp::typeSelect,
            $dp::typeInputText,
            $dp::typeTextarea,
            $dp::typeNumber,
            $dp::typeRange,
        ),
        'langs' => $this->locale->getLanguages(false),
        'langText' => array(
            'yes'    => _t('', 'Yes'),
            'no'     => _t('', 'No'),
            'all'    => _t('', 'All'),
            'select' => _t('', 'Select'),
        ),
        'typesAllowedParent' => array($dp::typeSelect),
        # these parameters correspond to the columns in the objects table (bff_test_posts)
        'datafield_int_last' => 15, # the number of the last field for a numeric property 
        'datafield_text_first' => 16, # the number of the first field for a text property 
        'datafield_text_last'  => 20, # the number of the last field for a text property 
        'searchRanges' => true,
        'cacheKey' => false,
    ));

    return $dp;
}

Using the object in the admin panel

You can find detailed information on how to use this component in lists and forms in this article