Components

Autocomplete Fields

When there are a large number of items to choose from in a dropdown list, such as subcategories or cities, it is convenient to replace select with an autocomplete field. To implement such a field, use the autocomplete(field_name, field_title, callback_search, callback_default, placeholder) method.

$form->autocomplete(
    'subcat_id',                      # form field `name` attribute                
    $this->langAdmin('Subcategory'),   # field title
    function ($query) {               # callback for autocomplete options
        $result = [];
        if (!empty($query)) {
            $filter = [
                ':q' => ['title LIKE :q', ':q' => '%'.$query.'%'],
            ];
            $data = $this->model->catsListing($filter); # get relevant data from the model
            foreach ($data as $v) {
                $result[] = [$v['id'], $v['title']];
        }    
        return $result;
    },
    function ($id) {  # callback for previously saved value 
        $data = $this->model->catData($id);
        return ! empty($data['title']) ? $data['title'] : '';
    }, 
    $this->langAdmin('Enter the subcategory name') # placeholder
);

The third parameter of the autocomplete() method is the callback for autocomplete options:

  • it takes the $query - search string, as an argument
  • it requires the necessary model method that will perform the search in the database table
  • it should return an array in the format [[$id_1, $title_1], [$id_2, $title_2], ...].

The next parameter is the callback for the previously saved value when editing a record from the list:

  • it takes the $id - the id of the subcategory of the current record, as an argument
  • it requires the necessary model method that will return the title value of the field
  • it should return a string with the title of the previously saved value or an empty string.

Tags

Tags allow you to add additional characteristics in the form of keywords to an object, which is convenient for searching in a list. You can learn more about creating the Tags component ($tagsComponent) from the article. To add and display tags in the admin controller, create a simple method:

/**
 * List of tags
 */
public function tags()
{
    # get the tag component object \bff\db\Tags
    $tagsComponent = $this->initTags(); 

    return $tagsComponent->manage();
}

The key is the call to the manage() method, which manages the list, the form for adding and editing tags.

We associate an object, for example a publication, with tags. To do this, we create a tag selection field in the add/edit publication form using the tagsComponent($tagsComponent, field_title, field_width) method of the form component.

$form->tagsComponent(
    $tagsComponent,            # tag component
    $this->langAdmin('Tags'),  # field title
    675                        # field width in px
);

There is an alternative way to use the tags field in the object (publication) form - the tags(field_name, field_title, callback_autocomplete, callback_default, is_rotate, placeholder) method of the form component.

$form->tags(
    'post_tags',               # form field 'name' attribute
    $this->langAdmin('Tags'),  # field title
    function ($query) {        # tags autocomplete callback
        $result = [];
        if (!empty($query)) {
            $filter = [
                ':q' => ['title LIKE :q', ':q' => '%'.$query.'%'],
            ];
            $data = $this->model->tagsListing($filter); # get relevant data from the model
            foreach ($data as $v) {
                $result[] = array($v['id'], $v['title']);
            }
        }
        return $result;
    },
    function ($ids) { # previously saved values callback
        $data = $this->model->tagsListing(['id' => $ids]);
        foreach ($data as & $v) {
            $v['value'] = $v['id'];
        }
        return $data;
    },
    true,
    'Enter a name, for example (one)'
);

The advantage of using this method to work with tags is that you can control the tag autocomplete in callback_autocomplete. This way, tags can be stored in a table of any kind and the form can be created and the list of tags can be defined in any convenient way. Similarly to the autocomplete field, the callback_autocomplete for the tags field:

  • receives $query as an argument - the search string,
  • requires the presence of the necessary model method, which will perform the search in the tags table in the database,
  • should return an array in the format [[ $id_tag_1, $title_tag_1 ], [ $id_tag_2, $title_tag_2 ], ...].

The next parameter is callback_default, which represents previously saved tags for the associated publication entity, which is relevant when editing:

  • takes $ids as an argument, which are the IDs of the previously saved tags in the format [ $tag_id_1, $tag_id_2, $tag_id_3, ... ],
  • requires the presence of the necessary model method, which will return the data for the searched tags,
  • the data must be in the format [[ 'title' => $title, 'value' => $id ], ...].

With this approach, we store the object tags as an array in the 'post_tags' field of the main object (publication) table of type TEXT, where the field name can be anything, the key is to ensure the correspondence with the field key in the form.

Publicator Content Builder

We recommend using Publicator as a content builder, which allows you to format text, upload images, add videos, make quotes, and headers. For more information about creating a Publicator component ($publicatorComponent) and setting its configuration $publicatorSettings, refer to the article.

Let's consider the Publicator as a form field in the admin panel. The declaration of such a content builder is quite simple, using the method publicator(field_name, field_search_name, is_lang, controls, settings). The parameters are the field name in the database, where the data from the builder will be stored as a JSON string, and the presence of a field for searching the text content of the content, which should be of type TEXT in the database table.

$form
    ->publicator(
        'content',       # data(field) of the constructor
        'content_search' # data(field) for text search
    );

Let's give an example of how to set allowed types of constructor blocks in the form, leaving the possibility to add only text and images:

$form->publicator(
    'content',                                  # data(field) of the constructor
    'content_search',                           # data(field) for text search
    true,                                       # use multilanguage
    [                                           # allowed blocks
        \bff\db\Publicator::blockTypeText,
        \bff\db\Publicator::blockTypePhoto,
    ], 
    $publicatorSettings                         # component settings
);

Dynamic Properties (Dynprops)

Dynamic properties allow you to add properties to an object comprehensively and conveniently use them when filtering by a list. You can read more about this component in this article.

Choosing Dynamic Properties

The choice of dynamic properties is made in the form of creating/editing an object in conjunction with the mandatory choice of the object category. Thus, when creating an object, we choose which category it will belong to, then we set the values of the properties of the selected category. In the form, we associate the category selection with adding a field of type "Dynamic Properties" using the dynprops(object_dp, field_owner) method, where the parameters are the Dynprops component object $dynpropsComponent and the name of the field of the selected category (cat_id):

$form->select('cat_id', $this->langAdmin('Category'), false, function($field) use($form) {
    # get the list of categories and create a list in the form of HTML::options
    $data = $this->model->catsListing();
    $result = [];
    if ( ! $form->recordID()) {
        # add the "Select" option for a new object
        $result[] = '<option value="0">'.$this->langAdmin('Select').'</option>';
    }
    $val = $field->value();
    foreach ($data as $v) {
        # mark the selected category (when editing)
        $result[] = '<option value="'.$v['id'].'"'.($val == $v['id'] ? ' selected="selected"' : '').'>'.$v['title'].'</option>';
    }
    return join('', $result);
);

# Specify that dynamic properties of the category should be displayed when selected from the list, pass the component object and the name of the category selection field
$form->dynprops($dynpropsComponent, 'cat_id');

Selected dynamic properties are saved along with other publication fields in the form save handler:

$form->onSave(function($id, $data) {
    return $this->model->postSave($id, $data);
});

Adding Dynamic Properties to the Category List

In the list of categories, the ability to add dynamic properties is available in the Actions column (next to editing and deleting). This is done using the onDynprops(dynpropsObject) method, where the parameter is the previously created dynamic properties component:

$list->onDynprops($dynpropsComponent);