Bitrix Refactoring to D7 ORM: Lower Support Costs

When we open a Bitrix project written several years ago, the first thing that catches the eye is global variables and concatenated SQL strings. Clients complain about slow catalog performance, and every new feature request turns into rewriting half the code. One of our clients, an auto parts onli

Our competencies:

Frequently Asked Questions

When we open a Bitrix project written several years ago, the first thing that catches the eye is global variables and concatenated SQL strings.

Clients complain about slow catalog performance, and every new feature request turns into rewriting half the code. One of our clients, an auto parts online store, was losing up to 15% of orders due to errors in delivery calculation caused by an outdated API. After refactoring to D7, we reduced the time to add new delivery methods from 3 days to 4 hours, and support costs dropped by 40%. In a project with 50,000 lines of code on the old API, every new feature cost three times more due to the need to work around global dependencies. Our refactoring is not "rewriting for the sake of rewriting" — it's about lowering support costs and eliminating the class of errors typical of procedural code. Support savings are substantial, with payback under 12 months. Contact us for a free assessment of your project.

What exactly changes when moving to D7

Global functions → DataManager methods:

// Before — old API $res = CIBlockElement::GetList( ['SORT' => 'ASC'], ['IBLOCK_ID' => 5, 'ACTIVE' => 'Y'], false, ['nPageSize' => 20], ['ID', 'NAME', 'PROPERTY_PRICE'] ); while ($arItem = $res->GetNextElement()) { $arFields = $arItem->GetFields(); $arProps = $arItem->GetProperties(); } // After — D7 ORM $result = \Bitrix\Iblock\Elements\ElementProductsTable::getList([ 'select' => ['ID', 'NAME', 'PROPERTY_PRICE_VALUE'], 'filter' => ['=IBLOCK_ID' => 5, '=ACTIVE' => 'Y'], 'order' => ['SORT' => 'ASC'], 'limit' => 20, ]); foreach ($result->fetchCollection() as $element) { $name = $element->getName(); $price = $element->get('PROPERTY_PRICE_VALUE'); } 

SQL strings → Connection API:

// Before — raw SQL with concatenation global $DB; $id = intval($id); // all the "protection" $res = $DB->Query("SELECT * FROM b_custom_table WHERE ID = " . $id); // After — parameterized queries $connection = \Bitrix\Main\Application::getConnection(); $result = $connection->query( "SELECT * FROM my_custom_table WHERE ID = ?", [$id] ); // or via SqlHelper for complex cases $helper = $connection->getSqlHelper(); $safeId = $helper->forSql((string)$id); 

Global $APPLICATION → Context and Application:

// Before global $APPLICATION; $APPLICATION->SetTitle('My page'); $APPLICATION->IncludeFile('/local/include/header.php'); // After — in component or controller context $this->arResult['PAGE_TITLE'] = 'My page'; // Inclusion via D7 mechanisms or Inertia/React approach 

Why the old API holds back development?

Security: concatenating SQL strings is a direct path to SQL injection. Performance: CIBlockElement::GetList() without limits dumps the entire table. Testability: global dependencies prevent isolating business logic. Read more about parameterized queries on Wikipedia.

How to carry out refactoring step by step?

Rewriting the entire project at once is a bad idea. Even a small online store contains 50,000+ lines of code. The right approach is layered refactoring with priority sorting.

Step-by-step refactoring plan
  1. Audit. Inventory of problem areas:
    • SQL queries with string concatenation (potential SQL injections)
    • Global variables in logic (global $DB, global $USER, global $APPLICATION)
    • Heavy queries via CIBlockElement::GetList without limits
    • Duplicate code for the same logic in different files
  2. Create a service layer. New service classes on D7 API for each area of responsibility. Old code calls new services.
  3. Gradual replacement. By modules and functional blocks. Each replaced block — regression testing.
  4. Remove obsolete code. Only after the new path is proven in production.

What is included in D7 refactoring?

Full codebase audit identifying critical areas, creation of a service layer and migration to D7 ORM, replacement of SQL queries with parameterized ones via Connection::query, setup of tagged caching and agents, regression testing of each replacement, documentation of the new architecture, training your team on D7. Guarantee on work performed is fixed in the contract.

Infoblocks: migration to D7 classes

From the current Bitrix version, auto-generated classes for infoblocks are available via Bitrix\Iblock\Elements:

// Enable in infoblock settings — "API code" flag // A class is generated with namespace Bitrix\Iblock\Elements $result = \Bitrix\Iblock\Elements\ElementCatalogTable::getList([ 'select' => ['ID', 'NAME', 'IBLOCK_SECTION_ID'], 'filter' => ['=ACTIVE' => 'Y'], ]); 

This is not a complete replacement for CIBlockElement — for writing (add/update), the old API is often still used since D7 wrappers for infoblock writing do not cover all scenarios.

Typical pitfalls during refactoring

Loss of events. If old code called CIBlockElement::Update(), event handlers (OnAfterIBlockElementUpdate) were attached. When moving to D7 methods, ORM events are different. Requires checking which handlers are tied to old events.

Difference in GetList vs getList results. CIBlockElement::GetList returns infoblock properties in a specific format with _VALUE, _ENUM_ID suffixes. ORM methods return a different structure. Code processing the result must be adapted.

Transactions. The old API did not always wrap operations in transactions. D7 provides explicit transactions:

$connection = \Bitrix\Main\Application::getConnection(); $connection->startTransaction(); try { // multiple operations $connection->commitTransaction(); } catch (\Throwable $e) { $connection->rollbackTransaction(); throw $e; } 

How do we guarantee quality?

We are certified 1C-Bitrix specialists with over 5 years of experience and more than 50 completed refactoring projects. We use style guides and automated testing. We provide a code warranty — if bugs are found due to our fault, we fix them free of charge within a month.

What to refactor first

Priority What Why
Critical SQL with string concatenation Security
High Heavy GetList without limits Performance
Medium Business logic in components Maintainability
Planned Stylistic global variables Readability

Timelines

Project volume Refactoring timeline
Small site (up to 30 logic files) 2–4 weeks
Medium online store (50–150 files) 2–3 months
Large portal or marketplace 4–8 months (staged)

Refactoring is technical debt that you pay now to avoid paying three times more in a year. Code on the old API does not become more reliable over time — with every Bitrix update, the risk of incompatibility grows. Get a consultation and project assessment — contact us for a detailed commercial proposal with a work plan.