Documentation

Creating a custom list of elements

Full example of admin page with list can be found here.

Basic principles

Generally, a Control Panel page displaying a list of elements requires the implementation of the following functions:

  • protection against unauthorized access;
  • obtaining a paginated list of elements;
  • ability to sort the list by any column;
  • ability to perform group and single actions on list elements;
  • perform the required actions on list elements.

The Control Panel page creation API allows to perform these functions independently. For example, a list can be built in such a way that it can be updated and navigated using AJAX without having to update the whole page.

Let us see how a Control Panel page with a list of elements can be created. Use the Subscription/Newsletter module page as example.

Prolog

Before we start the page output, we have to perform some preliminary steps. Create a file /bitrix/modules/subscribe/rubric_admin.php and add the following code to it:

<?php
use Bitrix\Main\Loader;
use Bitrix\Main\Localization\Loc;


// include all necessary files:
require_once($_SERVER["DOCUMENT_ROOT"]."/bitrix/modules/main/include/prolog_admin_before.php"); // the first common prologue

Loader::includeModule('subscribe'); // initialise the module
require_once($_SERVER["DOCUMENT_ROOT"]."/bitrix/modules/subscribe/prolog.php"); // a module prologue

// no need to include language file

// obtain the current user module access level to the
$POST_RIGHT = $APPLICATION->GetGroupRight("subscribe");
// if access is denied, direct the visitor to the authorization form
if ($POST_RIGHT == "D")
	$APPLICATION->AuthForm(Loc::getMessage("ACCESS_DENIED"));

// prepare all the data here
<?php
require($_SERVER["DOCUMENT_ROOT"]."/bitrix/modules/main/include/prolog_admin_after.php"); // the second common prologue // display the page here <?php require($_SERVER["DOCUMENT_ROOT"]."/bitrix/modules/main/include/epilog_admin.php");

Now we have the page body indicated on the figure above.

Now create a language file, for example: /bitrix/modules/subscribe/lang/com/rubric_admin.php for English language. In this file, create all language messages as the array elements: $MESS['message_identifier'] = "message_text";.

Since the /bitrix/modules/ catalog is not accessible via HTTP, create a file /bitrix/admin/rubric_admin.php:

<?php 
require($_SERVER["DOCUMENT_ROOT"]."/bitrix/modules/subscribe/admin/rubric_admin.php");
;

Now this file is available at: http://mysite.com/bitrix/admin/rubric_admin.php.


Page functions

As shown on the figure above, all page functions can be conditionally divided into several components:

  • Processing and preparing data
    • create instances required for class operation;
    • process actions on list elements;
    • configure and process filter of element list;
    • select list elements from database and prepare them for display;
    • specify table parameters (including sorting).
  • Data display
    • configure and display a Control Panel menu;
    • display filter;
    • display list.

For this, we need instances of the following classes:

Class Description
CAdminList Main class for handling Control Panel element lists.
CAdminResult The CDBResult class extension used with element lists in the Control Panel scripts.
CAdminSorting Used for list sorting.
CAdminFilter Used for list filtering.
Data handling

First, create instances of the CAdminList and CAdminSorting:

$sTableID = "tbl_rubric"; // table ID
$oSort = new CAdminSorting($sTableID, "ID", "desc"); // sorting object
$lAdmin = new CAdminList($sTableID, $oSort); // main object of the list
$by = mb_strtoupper($lAdmin->getField()); $order = mb_strtoupper($lAdmin->getOrder());

Result filter

In the example below, the result filter includes of the following parameters:

  • search by the mail list ID;
  • by the active mail list active state flag;
  • by the completion status.

The preparatory actions can be as follows:

// move filter validation to a separate function 
function CheckFilter()
{
global $FilterArr, $lAdmin;
foreach ($FilterArr as $f) global $$f;

/*
check values of $find_name variables and if an error occurs,
call $lAdmin->AddFilterError(" error_text").
*/

return count($lAdmin->arFilterErrors) == 0; // return false on error false;
}

// describe filter elements
$FilterArr = Array(
"find_id",
"find_lid",
"find_active",
"find_visible",
"find_auto",
);

// initialise the filter
$lAdmin->InitFilter($FilterArr);

// if all filter values are correct, process the filter
if (CheckFilter())
{
// create a filter array for CRubric::GetList() using the filter values
$arFilter = Array(
"ID" => $find_id,
"LID" => $find_lid,
"ACTIVE" => $find_active,
"VISIBLE" => $find_visible,
"AUTO" => $find_auto,
);
}

Handling actions on elements

The following two actions are possible with elements:

  • editing elements on the list page;
  • group and single actions with elements.

To verify that an action was performed on a list element, you can call CAdminList::EditAction() and CAdminList::GroupAction(). Don't forget to check permissions in both cases (here, check the write access permission for the Subscription module - $POST_RIGHT=="W").

Example:

// save modified elements
if($lAdmin->EditAction() && $POST_RIGHT=="W")
{
    // check the list of passed elements
    foreach($lAdmin->GetEditFields() as $ID=>$arFields)
    { 
		
		// save changes for each element 
$DB->StartTransaction();
$ID = IntVal($ID);
$cData = new CRubric;
if(($rsData = $cData->GetByID($ID)) && ($arData = $rsData->Fetch()))
{
foreach($arFields as $key=>$value)
$arData[$key]=$value;
if(!$cData->Update($ID, $arData))
{
$lAdmin->AddGroupError(Loc::getMessage("rub_save_error")." ".$cData->LAST_ERROR, $ID);
$DB->Rollback();
}
}
else
{
$lAdmin->AddGroupError(Loc::getMessage("rub_save_error")." ".Loc::getMessage("rub_no_rubric"), $ID);
$DB->Rollback();
}
$DB->Commit();
}
}

// process single and group actions
if(($arID = $lAdmin->GroupAction()) && $POST_RIGHT=="W")
{ // if "For all elements" is selected if ($lAdmin->IsGroupActionToAll()) { $cData = new CRubric;
$rsData = $cData->GetList(array($by=>$order), $arFilter);
while($arRes = $rsData->Fetch())
$arID[] = $arRes['ID']; } $action = $lAdmin->GetAction(); // walk the list of elements foreach($arID as $ID) { if(strlen($ID)<=0) continue; $ID = IntVal($ID); // perform the required action for each element switch($action) { // delete case "delete": @set_time_limit(0);
$DB->StartTransaction();
if(!CRubric::Delete($ID))
{
$DB->Rollback();
$lAdmin->AddGroupError(Loc::getMessage("rub_del_err"), $ID);
}
$DB->Commit();
break;

// activate or deactivate
case "activate":
case "deactivate":
$cData = new CRubric;
if(($rsData = $cData->GetByID($ID)) && ($arFields = $rsData->Fetch()))
{
$arFields["ACTIVE"]=($_REQUEST['action']=="activate"?"Y":"N");
if(!$cData->Update($ID, $arFields))
$lAdmin->AddGroupError(Loc::getMessage("rub_save_error").$cData->LAST_ERROR, $ID);
}
else
$lAdmin->AddGroupError(Loc::getMessage("rub_save_error")." ".Loc::getMessage("rub_no_rubric"), $ID);
break;
}

}
}

Selection of elements

The process of selection of elements is similar to that in a component or page except that an instance of the CAdminResult class needs to be created from the selection.

// select the list of mail lists 
$cData = new CRubric;
$rsData = $cData->GetList(array($by=>$order), $arFilter);

// transform the list into an instance of the CAdminResult class
$rsData = new CAdminResult($rsData, $sTableID);

// initialise pagewise navigation similar to CDBResult.
$rsData->NavStart();

// send the navigation code to $lAdmin
$lAdmin->NavText($rsData->GetNavPrint(Loc::getMessage("rub_nav")));

Prepare elements for output

In order to build a table of elements, we have to create an array of table headers; and then send the list of elements to  $lAdmin.The first action is performed by calling CAdminList::AddHeaders passing an array of table columns to it. Each column is described by an array, containing the following keys:

Key Description
id The column identifier.
content The column header.
sort The value of the GET request parameter for sorting.
default Specifies if a column is displayed in the list by default (true|false).

Example:

$lAdmin->AddHeaders(array(
array( "id" =>"ID",
"content" =>"ID",
"sort" =>"id",
"default" =>true,
),
array( "id" =>"NAME",
"content" =>Loc::getMessage("rub_name"),
"sort" =>"name",
"default" =>true,
),
array( "id" =>"LID",
"content" =>Loc::getMessage("rub_site"),
"sort" =>"lid",
"default" =>true,
),
array( "id" =>"SORT",
"content" =>Loc::getMessage("rub_sort"),
"sort" =>"sort",
"align" =>"right",
"default" =>true,
),
array( "id" =>"ACTIVE",
"content" =>Loc::getMessage("rub_act"),
"sort" =>"act",
"default" =>true,
),
array( "id" =>"VISIBLE",
"content" =>Loc::getMessage("rub_visible"),
"sort" =>"visible",
"default" =>true,
),
array( "id" =>"AUTO",
"content" =>Loc::getMessage("rub_auto"),
"sort" =>"auto",
"default" =>true,
),
array( "id" =>"LAST_EXECUTED",
"content" =>Loc::getMessage("rub_last_exec"),
"sort" =>"last_executed",
"default" =>true,
),
));

The list of elements is passed to the main object in the following way:

  1. Call CAdminList::AddRow(). Method result - link to an empty class instance CAdminListRow
  2. Create the fields using the following methods of CAdminListRow:
    • AddField - the cell value is displayed as specified when reading and editing the list;
    • AddViewField - specifies the field format for viewing;
    • AddEditField - specifies the field format for editing;
    • AddCheckField - the value is rendered and edited as a checkbox;
    • AddSelectField - the value is edited as a drop down list;
    • AddInputField - the value is edited in a text area field;
    • AddCalendarField - the value is edited as a date input field.
  3. Create the context menu for the row (CAdminListRow::AddActions())

You can combine different methods when creating a row field.

The element context menu is specified as an array whose elements are associated arrays with the following keys:

Key Description
ICON The CSS class name with an action button.
DISABLED Specifies whether the menu item is disabled or not (true|false).
DEFAULT Specifies whether the menu item is a default action (true|false). Double clicking the row activates the default action.
TEXT The menu item title.
TITLE The menu item tooltip.
ACTION The action to be performed performed when the menu item is activated (Javascript).
SEPARATOR Inserts a separator {true|false}. If true, all other keys will be ignored.

Example:

while($arRes = $rsData->NavNext(true, "f_")):
// create a row. the result is a CAdminListRow class instance $row =& $lAdmin->AddRow($f_ID, $arRes); // now configure the value display format   // for viewing and editing // the NAME parameter will be edited as a text and displayed as a link $row->AddInputField("NAME", array("size"=>20)); $row->AddViewField("NAME", '<a href="rubric_edit.php?id='.$f_id.'&lang='.lang.'">'.$f_name.'</a>'); // the LID parameter will be edited as a drop down list of languages $row->AddEditField("LID", CLang::SelectBox("LID", $f_LID)); // the SORT parameter will be edited as a text $row->AddInputField("SORT", array("size"=>20)); // the ACTIVE and VISIBLE flags will be edited as checkboxes $row->AddCheckField("ACTIVE"); $row->AddCheckField("VISIBLE"); // the AUTO parameter will be displayed as "Yes" or "No" in bold when edited $row->AddViewField("AUTO", $f_AUTO=="Y"?GetMessage("POST_U_YES"):GetMessage("POST_U_NO")); $row->AddEditField("AUTO", "<b>".($f_AUTO=="Y"?GetMessage("POST_U_YES"):GetMessage("POST_U_NO"))."</b>"); // create the context menu $arActions = Array(); // element editing $arActions[] = array( "ICON"=>"edit", "DEFAULT"=>true, "TEXT"=>GetMessage("rub_edit"), "ACTION"=>$lAdmin->ActionRedirect("rubric_edit.php?ID=".$f_ID) ); // element deletion if ($POST_RIGHT>="W") $arActions[] = array( "ICON"=>"delete", "TEXT"=>GetMessage("rub_del"), "ACTION"=>"if(confirm('".GetMessage('rub_del_conf')."')) ".$lAdmin->ActionDoGroup($f_ID, "delete") ); // insert a separator $arActions[] = array("SEPARATOR"=>true); // check the automated mail list template if (strlen($f_TEMPLATE)>0 && $f_AUTO=="Y") $arActions[] = array( "ICON"=>"", "TEXT"=>GetMessage("rub_check"), "ACTION"=>$lAdmin->ActionRedirect("template_test.php?ID=".$f_ID) ); // if the last item is separator, remove it. if(is_set($arActions[count($arActions)-1], "SEPARATOR")) unset($arActions[count($arActions)-1]); // apply the context menu to the row $row->AddActions($arActions); endwhile;

Now we have to add a table footer and assign group actions to elements to complete the table preparation.

The table resume is formed as an array whose elements are associated arrays with the following keys:

"title" - parameter name;
"value" - parameter value.

Additionally, the associated array may contain an entry "counter" set to true, which makes the element a table row selection counter. The value of "counter" will change dynamically whenever a user selects or deselects table rows.

A footer can be attached by calling CAdminList::AddFooter().

.

A list of possible group actions is specified as an array of elements in the format:

"action_identifier" => "action_name"

It can be attached to the table by calling CAdminList::AddGroupActionTable(). Processing group actions is discussed above.

Example:

// table footer 
$lAdmin->AddFooter(
array(
"TEXT"=>Loc::getMessage("POST_ADD"),
"LINK"=>"rubric_edit.php?lang=".LANG,
"TITLE"=>Loc::getMessage("POST_ADD_TITLE"),
"ICON"=>"btn_new",
),
);

// and attach it to the list
$lAdmin->AddAdminContextMenu($aContext);

Configuring Control Panel parameters

If required, you can assign the Control Panel menu which is displayed above the table (for users having the editing permissions). The menu is created as an array whose elements are associated arrays with the following keys:

Key Description
TEXT The menu item text.
TITLE The menu item tooltip.
LINK The button link.
LINK_PARAM Additional link parameters (will be added to the <A> tag).
ICON The button CSS class.
HTML Specifies the menu item HTML code.
SEPARATOR Specifies that an item is a separator (true|false).
NEWBAR Starts a new block of menu items (true|false).
MENU Creates a drop down menu.
The value is specified similarly to the table row context menu.

The context menu is attached by calling CAdminList::AddAdminContextMenu().

Example:

// build a menu consisting of only one item - "Add newsletter"
$aContext = array(
array(
"TEXT"=>Loc::getMessage("POST_ADD"),
"LINK"=>"rubric_edit.php?lang=".LANG,
"TITLE"=>Loc::getMessage("POST_ADD_TITLE"),
"ICON"=>"btn_new",
),
);

// and attach it to the list
$lAdmin->AddAdminContextMenu($aContext);

Final steps

Now the list preparation is completed. Call CAdminList::CheckListMode() to enable alternative rendering methods (AJAX, export to Excel):

// alternative display 
$lAdmin->CheckListMode();

Finally, set the page title immediately before output.

// set the page title
$APPLICATION->SetTitle(Loc::getMessage("rub_title"));

Data output

As the figure shows, the page preparation and the main output must be separated by including the system file prolog_admin_after.php:

// remember to separate data preparation from presentation 
require($_SERVER["DOCUMENT_ROOT"]."/bitrix/modules/main/include/prolog_admin_after.php");

As it has been mentioned above, data output can be split into two parts:

  • filter output;
  • list output.

Rendering the filter

To render the filter, we need to create a CAdminFilter class instance, pass the list of fields to it, and then build the filter form.

Example:

// create a filter object
$oFilter = new CAdminFilter(
  $sTableID."_filter",
  array(
    "ID",
    GetMessage("rub_f_site"),
    GetMessage("rub_f_active"),
    GetMessage("rub_f_public"),
    GetMessage("rub_f_auto"),
  )
);
?>
<form name="find_form" method="get" action="<?echo $APPLICATION->GetCurPage();?>">
<?$oFilter->Begin();?>
<tr>
  <td><?="ID"?>:</td>
  <td>
    <input type="text" name="find_id" size="47" value="<?echo htmlspecialchars($find_id)?>">
  </td>
</tr>
<tr>
  <td><?=GetMessage("rub_f_site").":"?></td>
  <td><input type="text" name="find_lid" size="47" value="<?echo htmlspecialchars($find_lid)?>"></td>
</tr>
<tr>
  <td><?=GetMessage("rub_f_active")?>:</td>
  <td>
    <?
    $arr = array(
      "reference" => array(
        GetMessage("POST_YES"),
        GetMessage("POST_NO"),
      ),
      "reference_id" => array(
        "Y",
        "N",
      )
    );
    echo SelectBoxFromArray("find_active", $arr, $find_active, GetMessage("POST_ALL"), "");
    ?>
  </td>
</tr>
<tr>
  <td><?=GetMessage("rub_f_public")?>:</td>
  <td><?echo SelectBoxFromArray("find_visible", $arr, $find_visible, GetMessage("POST_ALL"), "");?></td>
</tr>
<tr>
  <td><?=GetMessage("rub_f_auto")?>:</td>
  <td><?echo SelectBoxFromArray("find_auto", $arr, $find_auto, GetMessage("POST_ALL"), "");?></td>
</tr>
<?
$oFilter->Buttons(array("table_id"=>$sTableID,"url"=>$APPLICATION->GetCurPage(),"form"=>"find_form"));
$oFilter->End();
?>
</form>

Rendering the table

Having prepared all the required data, we can now render the report table just with one call:

// output the table of element list 
$lAdmin->DisplayList();

Here you can find the complete example of an administration page with the list.

You can find the complete example of creating an admin page with list here.


© «Bitrix24», 2001-2024
Up