O Bitrix é uma plataforma CMS empresarial poderosa, popular na Rússia e na Europa de Leste para a criação de websites corporativos, plataformas de e-commerce e soluções de intranet. Embora a sua curva de aprendizagem seja acentuada, dominar o desenvolvimento em Bitrix abre portas a projetos empresariais com requisitos complexos. Este guia aborda padrões essenciais de desenvolvimento em Bitrix na perspetiva de um programador sénior.
Porquê o Bitrix
O Bitrix oferece funcionalidades apelativas para ambientes empresariais:
- Plataforma Tudo-em-Um: CMS, CRM, e-commerce num único sistema
- Information Blocks: Estrutura flexível de gestão de conteúdos
- Módulos Integrados: Fóruns, blogs, e-commerce, workflows
- Funcionalidades Empresariais: Clustering, caching, suporte multi-site
- Mercado Russo: CMS dominante no setor empresarial russo
Compreender os Information Blocks (Infoblocks)
Os Infoblocks são a estrutura de dados central do Bitrix — pense neles como tipos de conteúdo configuráveis com propriedades, secções e elementos.
Visão Geral da Estrutura
Infoblock Type
└── Infoblock
├── Sections (categories)
└── Elements (content items)
└── Properties (custom fields)
Trabalhar com Infoblocks via API
<?php
// Incluir o kernel do Bitrix
require_once($_SERVER["DOCUMENT_ROOT"] . "/bitrix/modules/main/include/prolog_before.php");
// Carregar o módulo iblock
CModule::IncludeModule("iblock");
// Obter elementos do infoblock
$arFilter = array(
"IBLOCK_ID" => 5,
"ACTIVE" => "Y",
"SECTION_ID" => 10
);
$arSelect = array(
"ID",
"NAME",
"DETAIL_TEXT",
"PROPERTY_PRICE",
"PROPERTY_BRAND"
);
$res = CIBlockElement::GetList(
array("SORT" => "ASC"), // Ordenação
$arFilter, // Filtro
false, // Agrupamento
false, // Navegação
$arSelect // Selecionar campos
);
while ($element = $res->GetNextElement()) {
$fields = $element->GetFields();
$props = $element->GetProperties();
echo $fields["NAME"] . ": " . $props["PRICE"]["VALUE"] . "<br>";
}
?>
Criar Elementos de Infoblock
<?php
CModule::IncludeModule("iblock");
$element = new CIBlockElement;
$arFields = array(
"IBLOCK_ID" => 5,
"IBLOCK_SECTION_ID" => 10,
"NAME" => "New Product",
"ACTIVE" => "Y",
"PREVIEW_TEXT" => "Short description",
"DETAIL_TEXT" => "Full product description",
"PROPERTY_VALUES" => array(
"PRICE" => 1999,
"BRAND" => "Samsung",
"FEATURES" => array("Feature 1", "Feature 2")
)
);
if ($elementId = $element->Add($arFields)) {
echo "Element created with ID: " . $elementId;
} else {
echo "Error: " . $element->LAST_ERROR;
}
?>
Copiar Propriedades e Formulários de Infoblock
Quando tem vários infoblocks do mesmo tipo e precisa de copiar configurações de formulários:
<?php
require_once($_SERVER["DOCUMENT_ROOT"] . "/bitrix/modules/main/bx_root.php");
require_once($_SERVER["DOCUMENT_ROOT"] . BX_PERSONAL_ROOT . "/modules/main/include/prolog_before.php");
if (!defined("B_PROLOG_INCLUDED") || B_PROLOG_INCLUDED !== true) die();
CModule::IncludeModule("iblock");
if (intval($_REQUEST["IBLOCK_ID_FORMS"]) > 0 && !empty($_REQUEST["IBLOCK_TYPE_ID"])) {
$masterIblockId = intval($_REQUEST["IBLOCK_ID_FORMS"]);
$iblockTypeId = $_REQUEST["IBLOCK_TYPE_ID"];
// Obter propriedades do infoblock mestre
$masterProperties = array();
$dbProperties = CIBlockProperty::GetList(
array("sort" => "asc", "name" => "asc"),
array("ACTIVE" => "Y", "IBLOCK_ID" => $masterIblockId)
);
while ($property = $dbProperties->GetNext()) {
$masterProperties[$property['CODE']] = 'PROPERTY_' . $property['ID'];
}
// Definições a copiar
$settings = array(
array('name' => 'form_element_#ID#', 'group' => 'form'),
array('name' => 'form_section_#ID#', 'group' => 'form'),
array('name' => 'tbl_iblock_list_#MD5#', 'group' => 'list'),
array('name' => 'tbl_iblock_element_#MD5#', 'group' => 'list'),
);
// Obter definições do mestre
foreach ($settings as $key => $value) {
$name = str_replace(
array('#ID#', '#MD5#'),
array($masterIblockId, md5($iblockTypeId . "." . $masterIblockId)),
$value['name']
);
$settings[$key]['value'] = CUserOptions::GetOption($value['group'], $name);
}
// Aplicar a todos os infoblocks do mesmo tipo
$dbResult = CIBlock::GetList(
array(),
array('=TYPE' => $iblockTypeId, '!ID' => $masterIblockId),
true
);
while ($iblock = $dbResult->Fetch()) {
// Mapear IDs de propriedades
$search = array();
$replacement = array();
$dbProps = CIBlockProperty::GetList(
array("sort" => "asc"),
array("ACTIVE" => "Y", "IBLOCK_ID" => $iblock['ID'])
);
while ($prop = $dbProps->GetNext()) {
if (!empty($masterProperties[$prop['CODE']])) {
$search[] = $masterProperties[$prop['CODE']];
$replacement[] = 'PROPERTY_' . $prop['ID'];
}
}
// Copiar definições com mapeamento de propriedades
foreach ($settings as $value) {
$name = str_replace(
array('#ID#', '#MD5#'),
array($iblock['ID'], md5($iblock['IBLOCK_TYPE_ID'] . "." . $iblock['ID'])),
$value['name']
);
$newValue = array();
foreach ($value['value'] as $k => $string) {
$newValue[$k] = str_replace($search, $replacement, $string);
}
CUserOptions::DeleteOption($value['group'], $name);
CUserOptions::SetOption($value['group'], $name, $newValue, true);
}
}
echo "Forms copied successfully!";
}
?>
Administração do Fórum
O Bitrix inclui um módulo de fórum integrado. Eis como gerir o conteúdo do fórum programaticamente.
Eliminar Todas as Mensagens de um Utilizador
Útil para remover spam:
<?php
// Configuração
$badUserId = 29541;
// Eliminar as mensagens do utilizador
$deleteMessages = "DELETE FROM b_forum_message WHERE author_id = $badUserId";
// Atualizar metadados do tópico após a eliminação
$updateTopics = "UPDATE b_forum_topic as t
LEFT JOIN (
SELECT
MAX(gm.id) as id,
gm.topic_id,
MAX(gm.post_date) as post_date
FROM b_forum_message as gm
GROUP BY topic_id
) as g ON t.id = g.topic_id
LEFT JOIN b_forum_message as m ON m.id = g.id
SET
t.last_message_id = g.id,
t.last_poster_id = m.author_id,
t.last_poster_name = m.author_name,
t.last_post_date = g.post_date,
t.abs_last_message_id = g.id,
t.abs_last_poster_id = m.author_id,
t.abs_last_poster_name = m.author_name,
t.abs_last_post_date = g.post_date
WHERE t.abs_last_message_id <> g.id";
// Ligar utilizando a configuração do Bitrix
include $_SERVER["DOCUMENT_ROOT"] . '/bitrix/php_interface/dbconn.php';
$db = mysqli_connect($DBHost, $DBLogin, $DBPassword, $DBName);
mysqli_set_charset($db, 'utf8');
mysqli_query($db, $deleteMessages);
mysqli_query($db, $updateTopics);
echo "Spam removed and topics updated.";
?>
Desenvolvimento de Componentes
O Bitrix utiliza componentes para funcionalidade reutilizável.
Estrutura Básica de um Componente
/local/components/mycompany/mycomponent/
├── .description.php # Metadados do componente
├── .parameters.php # Definição de parâmetros de entrada
├── component.php # Lógica principal
├── class.php # Classe de componente em OOP
└── templates/
└── .default/
├── template.php
├── style.css
└── script.js
Exemplo de Classe de Componente
<?php
// /local/components/mycompany/product.list/class.php
if (!defined("B_PROLOG_INCLUDED") || B_PROLOG_INCLUDED !== true) die();
use Bitrix\Main\Loader;
class ProductListComponent extends CBitrixComponent
{
protected function checkModules()
{
if (!Loader::includeModule('iblock')) {
throw new \Exception('Module iblock not installed');
}
}
protected function getProducts()
{
$products = array();
$filter = array(
"IBLOCK_ID" => $this->arParams["IBLOCK_ID"],
"ACTIVE" => "Y"
);
if (!empty($this->arParams["SECTION_ID"])) {
$filter["SECTION_ID"] = $this->arParams["SECTION_ID"];
}
$res = \CIBlockElement::GetList(
array("SORT" => "ASC"),
$filter,
false,
array("nPageSize" => $this->arParams["PAGE_SIZE"]),
array("ID", "NAME", "PREVIEW_PICTURE", "DETAIL_PAGE_URL")
);
while ($element = $res->GetNextElement()) {
$fields = $element->GetFields();
$fields["PROPERTIES"] = $element->GetProperties();
$products[] = $fields;
}
return $products;
}
public function executeComponent()
{
try {
$this->checkModules();
$this->arResult["PRODUCTS"] = $this->getProducts();
$this->includeComponentTemplate();
} catch (\Exception $e) {
ShowError($e->getMessage());
}
}
}
?>
D7 (API Moderna)
O Bitrix D7 é a API moderna baseada em ORM:
<?php
use Bitrix\Main\Loader;
use Bitrix\Iblock\ElementTable;
Loader::includeModule('iblock');
// Consulta com D7
$elements = ElementTable::getList(array(
'select' => array('ID', 'NAME', 'IBLOCK_ID'),
'filter' => array(
'=IBLOCK_ID' => 5,
'=ACTIVE' => 'Y'
),
'order' => array('SORT' => 'ASC'),
'limit' => 10
));
while ($element = $elements->fetch()) {
echo $element['NAME'] . "<br>";
}
// Usar DataManager para tabelas personalizadas
use Bitrix\Main\Entity;
class MyCustomTable extends Entity\DataManager
{
public static function getTableName()
{
return 'my_custom_table';
}
public static function getMap()
{
return array(
'ID' => new Entity\IntegerField('ID', array(
'primary' => true,
'autocomplete' => true
)),
'NAME' => new Entity\StringField('NAME', array(
'required' => true
)),
'CREATED_AT' => new Entity\DatetimeField('CREATED_AT')
);
}
}
?>
Event Handlers
Registe handlers para eventos do Bitrix:
<?php
// /local/php_interface/init.php
AddEventHandler("iblock", "OnBeforeIBlockElementAdd", "MyOnBeforeElementAdd");
AddEventHandler("iblock", "OnAfterIBlockElementAdd", "MyOnAfterElementAdd");
function MyOnBeforeElementAdd(&$arFields)
{
// Validar ou modificar antes de guardar
if (empty($arFields["NAME"])) {
global $APPLICATION;
$APPLICATION->ThrowException("Name is required");
return false;
}
// Gerar código automaticamente a partir do nome
$arFields["CODE"] = CUtil::translit(
$arFields["NAME"],
"ru",
array("replace_space" => "-", "replace_other" => "-")
);
return true;
}
function MyOnAfterElementAdd(&$arFields)
{
// Registar em log ou notificar após guardar
CEventLog::Add(array(
"SEVERITY" => "INFO",
"AUDIT_TYPE_ID" => "IBLOCK_ELEMENT_ADD",
"MODULE_ID" => "iblock",
"ITEM_ID" => $arFields["ID"],
"DESCRIPTION" => "Element added: " . $arFields["NAME"]
));
}
?>
Caching
O Bitrix disponibiliza mecanismos de caching poderosos:
<?php
$cacheTime = 3600; // 1 hora
$cacheId = "my_cache_" . $IBLOCK_ID . "_" . $SECTION_ID;
$cachePath = "/my_component/";
$cache = new CPHPCache();
if ($cache->InitCache($cacheTime, $cacheId, $cachePath)) {
// Obter da cache
$vars = $cache->GetVars();
$arResult = $vars["arResult"];
} elseif ($cache->StartDataCache()) {
// Gerar dados
$arResult = getExpensiveData();
// Guardar na cache
$cache->EndDataCache(array("arResult" => $arResult));
}
?>
Principais Conclusões
- Aprenda Infoblocks: Núcleo da gestão de conteúdos no Bitrix
- Use a API D7: Abordagem moderna baseada em ORM
- Arquitetura de componentes: Unidades de funcionalidade reutilizáveis
- Orientado a eventos: Estenda o comportamento através de handlers
- Use caching de forma agressiva: Essencial para o desempenho
- Conhecimento de base de dados: SQL direto por vezes é necessário
O Bitrix tem uma curva de aprendizagem acentuada, mas recompensa o investimento com capacidades empresariais poderosas — domine estes fundamentos e irá lidar com projetos Bitrix complexos com confiança.