Часть 6. Код публичной части гостевой книги
Нам потребуются два компонента публичной части – список записей гостевой книги и форма редактирования/добавления новой записи. Начнем с простого, то есть, со списка записей. Этот компонент реализуется кодом, заимствованным из списка новостей:
<?
IncludeTemplateLangFile(__FILE__);
require_once($_SERVER["DOCUMENT_ROOT"]."/bitrix/modules/ix_guestbook/include.php");
$ID = (isset($ID) ? $ID : $_REQUEST["ID"]);
$IBLOCK_TYPE = (isset($IBLOCK_TYPE) ? $IBLOCK_TYPE : "guestbook");
$NEWS_COUNT = (strlen($NEWS_COUNT)>0 ? intval($NEWS_COUNT) : "20");
$SORT_BY1 = (isset($SORT_BY1) ? $SORT_BY1 : "ACTIVE_FROM");
$SORT_ORDER1 = (isset($SORT_ORDER1) ? $SORT_ORDER1 : "DESC");
$SORT_BY2 = (isset($SORT_BY2) ? $SORT_BY2 : "SORT");
$SORT_ORDER2 = (isset($SORT_ORDER2) ? $SORT_ORDER2 : "ASC");
$SORT = Array($SORT_BY1=>$SORT_ORDER1, $SORT_BY2=>$SORT_ORDER2);
if(CModule::IncludeModule("iblock") && ($arIBlock = GetIBlock($ID, $IBLOCK_TYPE))):
$APPLICATION->SetTitle($arIBlock["NAME"]);
$APPLICATION->AddChainItem($arIBlock["NAME"]);
$items = GetIBlockElementList($ID, false, $SORT, $NEWS_COUNT);
$items->NavPrint(GetMessage("T_IX_GB_NAVIG"));
while($obItem = $items->GetNextElement()):
$arItem = $obItem->GetFields();
?>
<p class="text">
<?echo $arItem["DATE_ACTIVE_FROM"];?> :: <b><?echo $arItem["NAME"]?></b></a><br>
<?echo $arItem["PREVIEW_TEXT"];?><br>
</p>
<?
endwhile;
$items->NavPrint(GetMessage("T_IX_GB_NAVIG"));
else:
ShowError(GetMessage("T_IX_GB_NA"));
endif;
?>
Этот код мы вставим в файле «/ix_guestbook/install/templates/ix_guestbook/index.php». Самое важное здесь – это разместить файл в каталоге «templates/ix_guestbook/», а собственно название файла не является обязательным. Данный код самым банальным образом выводит список элементов заданного инфоблока. «А мне больше и не надо!»
Второй компонент должен управлять записями гостевой книги – добавлять новые, редактировать и удалять существующие. Поскольку, как уже было сказано, наша основная методика – это copy/paste, то и сейчас нужный нам код мы возьмем готовый и лишь слегка адаптируем его под наши нужды. Нам нужна форма добавления и редактирования элемента инфоблока. Совершенно очевидно, что такой код в системе уже есть, поскольку мы можем редактировать элементы в разделе «Администрирование». Нужный нам файл мы нашли в модуле iblock: «/iblock/admin/iblock_element_edit.php».
Скопируем этот файл в наш модуль под другим названием: «/ix_guestbook/install/templates/ix_guestbook/edit_record.php». Теперь нам надо сократить его, поскольку вся функциональность нам не нужна. Что войдет в запись гостевой книги? Имя пользователя (или его псевдоним и т.д.) и текст. Проецируя это на свойства инфоблоков, становится очевидным, что нам нет нужды заводить дополнительные параметры. Для имени пользователя мы воспользуемся полем «Название» элемента инфоблока (поскольку пользователь может быть анонимом), а для текста нам хватит поля «PREVIEW_TEXT». Для модерирования мы пользуемся свойством Active, таким образом, мы избежим сложностей с использованием статусов инфоблоков в рамках документооборота.
«edit_record.php» должен реализовывать простую логику:
- Если нам передают запись для редактирования, то мы генерируем форму и заполняем ее значениями;
- Если нам не передают запись, то мы генерируем форму и позволяем заполнить новую запись;
- Если нам передают заполненные свойства записи, то мы сохраняем изменения в базе данных;
- Если нам передают идентификатор записи для удаления, то мы ее удаляем.
Код для генерирования формы и сохранения заполненных свойств мы позаимствуем из «iblock_element_edit.php», а остальное допишем сами. В результате получается следующее:
<?
require_once($_SERVER["DOCUMENT_ROOT"]."/bitrix/modules/iblock/iblock.php");
require_once($_SERVER["DOCUMENT_ROOT"]."/bitrix/modules/iblock/prolog.php");
IncludeModuleLangFile(__FILE__);
require_once($_SERVER["DOCUMENT_ROOT"]."/bitrix/modules/ix_guestbook/include.php");
$bModerator = (CIX_Guestbook::IsModerator()) ? "Y" : "N";
$bUser = (CIX_Guestbook::IsUser()) ? "Y" : "N";
if($bModerator!="Y" && $bUser!="Y") $APPLICATION->AuthForm(GetMessage("ACCESS_DENIED"));
$strWarning = "";
$ID = IntVal($ID); //код постоянной записи
$del_id = IntVal($del_id);
$WF_ID = $ID; //код текущей редактируемой записи
$IBLOCK_ID = IntVal($IBLOCK_ID); //код информационного раздела
$WF = "N";
$view = "N";
if(strlen($return_url)>0 && strtolower(substr($return_url, strlen($APPLICATION->GetCurPage())))==strtolower($APPLICATION->GetCurPage()))
$return_url = "";
class _CIBlockError
{
var $err_type, $err_text, $err_level;
function _CIBlockError($err_level, $err_type, $err_text)
{
$this->err_type = $err_type;
$this->err_text = $err_text;
$this->err_level = $err_level;
}
}
$error = false;
if ($del_id > 0) {
$DB->StartTransaction();
if(!CIBlockElement::Delete($del_id))
{
$strWarning.=GetMessage("IBLOCK_DELETE_ERROR");
$DB->Rollback();
}
else
$DB->Commit();
LocalRedirect($return_url);
}
elseif ($_POST["form_filled"] == "") {
$str_ACTIVE="Y";
$str_SORT="500";
if (COption::GetOptionString("ix_guestbook", "ix_gb_html_default", "N")=="Y") { $str_PREVIEW_TEXT_TYPE="html"; }
else {$str_PREVIEW_TEXT_TYPE="text"; }
// $str_PREVIEW_TEXT_TYPE="html";
$str_DETAIL_TEXT_TYPE="html";
if(!$error && CModule::IncludeModule("workflow") && $view!="Y") CIblockElement::WF_Lock($ID);
$str_IBLOCK_ELEMENT_SECTION = Array();
$result = CIBlockElement::GetByID($WF_ID);
$arIBTYPE = CIBlockType::GetByIDLang($type, LANG);
if($arIBTYPE===false)
{
$error = new _CIBlockError(1, "BAD_IBLOCK_TYPE", GetMessage("IBLOCK_BAD_BLOCK_TYPE_ID"));
break;
}
$bBadBlock = true;
$iblock = CIBlock::GetByID($IBLOCK_ID);
if($arIBlock=$iblock->Fetch())
{
$bBadBlock = ($bModerator == "Y") OR ($bUser = "Y");
}
if($ar = $result->ExtractFields("str_"))
{
if($str_IN_SECTIONS=="N")
$str_IBLOCK_ELEMENT_SECTION[] = 0;
else
{
$result = CIBlockElement::GetElementGroups($WF_ID);
while($ar = $result->Fetch())
$str_IBLOCK_ELEMENT_SECTION[] = $ar["ID"];
}
}
else
{
$WF_ID=0;
$ID=0;
if($IBLOCK_SECTION_ID>0)
$str_IBLOCK_ELEMENT_SECTION[] = $IBLOCK_SECTION_ID;
}
if($ID>0)
{
if($view=="Y")
$APPLICATION->SetTitle($arIBlock["NAME"].": ".$arIBTYPE["ELEMENT_NAME"].": ".$str_NAME." - ".GetMessage("IBLOCK_ELEMENT_EDIT_VIEW"));
else
$APPLICATION->SetTitle($arIBlock["NAME"].": ".$arIBTYPE["ELEMENT_NAME"].": ".$str_NAME." - ".GetMessage("IBLOCK_EDIT_TITLE"));
}
else
$APPLICATION->SetTitle($arIBlock["NAME"].": ".$arIBTYPE["ELEMENT_NAME"].": ".GetMessage("IBLOCK_NEW_TITLE"));
require($_SERVER["DOCUMENT_ROOT"]."/bitrix/modules/main/include/prolog_after.php");
// Далее форма редактирования записи
if ($error) ShowError($error->err_text);
//НАЧАЛО настраиваемой формы
if (strlen($arIBTYPE["EDIT_FILE_AFTER"])>0 && is_file($_SERVER["DOCUMENT_ROOT"].$arIBTYPE["EDIT_FILE_AFTER"])):
include($_SERVER["DOCUMENT_ROOT"].$arIBTYPE["EDIT_FILE_AFTER"]);
else:
$form_filled = "Y";
?>
<form method="POST" action="<? echo $APPLICATION->GetCurPage()?>" ENCTYPE="multipart/form-data" name="form_element">
<? echo GetFilterHiddens("filter_"); ?>
<input type="hidden" name="form_filled" value="<? echo $form_filled;?>">
<input type="hidden" name="from" value="<?echo htmlspecialchars($from)?>">
<input type="hidden" name="WF" value="<?echo htmlspecialchars($WF)?>">
<input type="hidden" name="return_url" value="<?echo $return_url?>">
<input type="hidden" name="ID" value="<?echo $ID?>">
<input type="hidden" name="type" value="<?echo $type?>">
<input type="hidden" name="IBLOCK_SECTION_ID" value="<?echo IntVal($IBLOCK_SECTION_ID)?>">
<input type="hidden" name="IBLOCK_ID" value="<?echo IntVal($IBLOCK_ID)?>">
<table border="0" cellspacing="1" cellpadding="3" class="edittable" width="100%">
<?
if($ID > 0):
$p = CIblockElement::GetByID($ID);
$pr = $p->Fetch();
$str_NAME = $pr["NAME"];
$str_PREVIEW_TEXT = $pr["PREVIEW_TEXT"];
endif;?>
<tr>
<td valign="top" align="left"><font class="tablefieldtext"><font class="required">*</font><?echo GetMessage("IX_GB_USERNAME")?></font></td>
<td valign="top">
<? if ($str_NAME == "") $str_NAME = $USER->GetFullName()?>
<input type="text" name="NAME" size="50" maxlength="255" class="typeinput" value="<?echo $str_NAME?>">
</td>
</tr>
<?if(COption::GetOptionString("ix_guestbook", "ix_gb_html", "N")=="Y"):?>
<?if(ereg('(MSIE|Internet Explorer) ([0-9]).([0-9])+', $_SERVER['HTTP_USER_AGENT'], $version) && IntVal($version[2])>=5 && COption::GetOptionString("iblock", "use_htmledit", "Y")=="Y" && CModule::IncludeModule("fileman")):?>
<tr>
<td valign="top" colspan="2">
<?CFileMan::AddHTMLEditorFrame("PREVIEW_TEXT", $str_PREVIEW_TEXT, "PREVIEW_TEXT_TYPE", $str_PREVIEW_TEXT_TYPE, 300);?>
</td>
</tr>
<?else:?>
<tr>
<td valign="top" align="right"><font class="tablefieldtext"><?echo GetMessage("IBLOCK_DESC_TYPE")?></font></td>
<td valign="top">
<font class="tablebodytext">
<input type="radio" name="PREVIEW_TEXT_TYPE" value="text"<?if($str_PREVIEW_TEXT_TYPE!="html")echo " checked"?>> <?echo GetMessage("IBLOCK_DESC_TYPE_TEXT")?> / <input type="radio" name="PREVIEW_TEXT_TYPE" value="html"<?if($str_PREVIEW_TEXT_TYPE=="html")echo " checked"?>> <?echo GetMessage("IBLOCK_DESC_TYPE_HTML")?>
</font>
</td>
</tr>
<tr>
<td valign="top" align="center"colspan="2" width="100%">
<textarea cols="110" class="typearea" rows="10" name="PREVIEW_TEXT" wrap="virtual"><?echo $str_PREVIEW_TEXT?></textarea>
</td>
</tr>
<?endif?>
<?else:?>
<tr>
<td valign="top" align="left" colspan="2" width="100%">
<textarea cols="80" class="typearea" rows="10" name="PREVIEW_TEXT" wrap="virtual"><?echo $str_PREVIEW_TEXT?></textarea>
</td>
</tr>
<?endif?>
</table>
<br>
<input type="submit" class="button" name="save" value="<?echo (($ID > 0)?GetMessage('IBLOCK_SAVE'):GetMessage('IBLOCK_ADD'))?>">
</form>
<? endif;
// Окончание формы
}
else {
do{ //цикл из одной итерации для выхода по break
$arIBTYPE = CIBlockType::GetByIDLang($type, LANG);
if($arIBTYPE===false)
{
$error = new _CIBlockError(1, "BAD_IBLOCK_TYPE", GetMessage("IBLOCK_BAD_BLOCK_TYPE_ID"));
break;
}
$iblock = CIBlock::GetByID($IBLOCK_ID);
$arIBlock=$iblock->Fetch();
if(strlen($arIBTYPE["EDIT_FILE_BEFORE"])>0 && is_file($_SERVER["DOCUMENT_ROOT"].$arIBTYPE["EDIT_FILE_BEFORE"]))
{
include($_SERVER["DOCUMENT_ROOT"].$arIBTYPE["EDIT_FILE_BEFORE"]);
}
if ($view!="Y" && (!$error) && empty($dontsave))
{
if ($WF=="Y" && CModule::IncludeModule("workflow") && intval($_POST["WF_STATUS_ID"])<=0)
$strWarning .= GetMessage("IBLOCK_WRONG_WF_STATUS")."<br>";
elseif($WF=="Y" && CModule::IncludeModule("workflow") && CIBlockElement::WF_GetStatusPermission($_POST["WF_STATUS_ID"])<1)
$strWarning .= GetMessage("IBLOCK_ACCESS_DENIED_STATUS")." [".$_POST["WF_STATUS_ID"]."]."."<br>";
else
{
$DB->StartTransaction();
$bs = new CIBlockElement;
// Для премодерируемой книги Active = "N"
if ($ID == 0) {
$today = getdate();
$str_today = $today["mon"]."/".$today["mday"]."/".$today["year"];
$str_today = $DB->FormatDate($str_today, "MM/DD/YYYY", CLang::GetDateFormat("SHORT"));
$str_today .= " ".$today["hours"].":".$today["minutes"].":".$today["seconds"];
}
else {$str_today = $_POST["ACTIVE_FROM"]; }
$arFields = Array(
"ACTIVE" => "Y",
"MODIFIED_BY" => $USER->GetID(),
"IBLOCK_SECTION" => $_POST["IBLOCK_SECTION"],
"IBLOCK_ID" => $IBLOCK_ID,
"ACTIVE_FROM" => $str_today,
"NAME" => $_POST["NAME"],
"PREVIEW_TEXT" => $_POST["PREVIEW_TEXT"],
"PREVIEW_TEXT_TYPE" => $_POST["PREVIEW_TEXT_TYPE"]
);
if(COption::GetOptionString("iblock", "show_xml_id", "N")=="Y" && is_set($_POST, "XML_ID"))
{
$arFields["XML_ID"] = $_POST["XML_ID"];
}
if($ID>0)
$res = $bs->Update($ID, $arFields, $WF=="Y");
else
{
$ID = $bs->Add($arFields, CModule::IncludeModule("workflow"));
$res = ($ID>0);
$PARENT_ID = $ID;
}
if(!$res)
$strWarning .= $bs->LAST_ERROR."<br>";
else
CIBlockElement::RecalcSections($ID);
}
if(strlen($strWarning)>0)
{
$error = new _CIBlockError(2, "BAD_SAVE", $strWarning);
$bVarsFromForm = true;
$DB->Rollback();
}
else
{
if(CModule::IncludeModule("workflow"))
CIBlockElement::WF_UnLock($ID);
$arFields['ID'] = $ID;
if(function_exists('BXIBlockAfterSave'))
BXIBlockAfterSave($arFields);
$DB->Commit();
LocalRedirect($return_url);
}
}
if(!empty($dontsave))
{
if(CModule::IncludeModule("workflow"))
CIBlockElement::WF_UnLock($ID);
LocalRedirect($return_url);
}
}while(false);
echo $error;
}
require($_SERVER["DOCUMENT_ROOT"]."/bitrix/modules/main/include/epilog.php");
?>
В параметре $del_id нам будут передавать идентификатор записи для удаления, в массиве $_POST передаются значения свойств записи, при этом, если $ID (идентификатор записи) отличен от нуля, то это означает, что мы редактируем существующую запись. В противном случае речь идет про добавление новой. Сохранение записи происходит при помощи кода:
$arFields = Array(
"ACTIVE" => "Y",
"MODIFIED_BY" => $USER->GetID(),
"IBLOCK_SECTION" => $_POST["IBLOCK_SECTION"],
"IBLOCK_ID" => $IBLOCK_ID,
"ACTIVE_FROM" => $str_today,
"NAME" => $_POST["NAME"],
"PREVIEW_TEXT" => $_POST["PREVIEW_TEXT"],
"PREVIEW_TEXT_TYPE" => $_POST["PREVIEW_TEXT_TYPE"]
);
if($ID>0)
$res = $bs->Update($ID, $arFields, $WF=="Y");
else
{
$ID = $bs->Add($arFields, CModule::IncludeModule("workflow"));
$res = ($ID>0);
$PARENT_ID = $ID;
}
Обратим внимание на код, связанный с распределением прав:
$bModerator = (CIX_Guestbook::IsModerator()) ? "Y" : "N";
$bUser = (CIX_Guestbook::IsUser()) ? "Y" : "N";
if($bModerator!="Y" && $bUser!="Y") $APPLICATION->AuthForm(GetMessage("ACCESS_DENIED"));
Очевидно, что он позволяет добавлять записи только пользователям, имеющим соответствующие роли. Ради этих трех строчек мы и описывали методы класса CIX_Guestbook.
Дальнейший анализ кода приведенного выше поручаем вам самим, тем более, что его можно еще долго оптимизировать. Наша задача – продемонстрировать интеграцию с БУС, поэтому мы переходим к следующему пункту – регистрации компонентов в HTML-редакторе.