
Пост ненависти или впечатления от Битрикса
Добрый день, уважаемые читатели и случайные посетители данного блога. На данный момент уже кучу времени я занят над разработкой нового и оригинального сервиса, который принесет миллионы который в теории может перерасти в популярный проект, так что времени на блог у меня совсем мало. Тем не менее по воле случая мне пришлось иметь дело с одной жуткой системой, имя которой 1с-Битрикс, о которой я и попробую выразить свое субъективное, полное ненависти и баттхерта мнение
Для кого собственно эта статья — для разработчиков, которые ранее не имели ничего общего с этой CMS, опытные же битриксоиды закидают меня помидорами, отправят вкуривать мануалы, скажут что я не умею его готовить и назовут кучей обидных слов. А так же для заказчиков, которые вполне смогут сэкономить некоторое количество денег на хостинге, разработке, поддержке и ежегодном продлении лицензии.
Для начала вкратце распишу свою задачу — создание интернет-магазина электроники с кошеным дизайном и интеграцией с порождением ада — 1С. И если бы не халявно добытая редакция «Малый бизнес», то я с легкостью убедил бы заказчиков создать интернет-магазин на OpenCart. Но увы, придется работать с тем, что есть.
Стадия 1 — Подготовка
— Где можно оправданно использовать Битрикс?
— В анекдотах.
Для начала нужно скачать и установить данное решение. Здесь все просто — идем на сайт битрикса и качаем нужную редакцию.
Итак, имеем 36 тысяч файлов. С установкой проблем не возникает, получаем интернет-магазин с «адаптивной версткой».
Стадия 2 — Взгляд изнутри
Будем считать, что с установкой все справились и получили демо-магазин одежды на своем локальном сервере. Давайте немного глянем внутрь, с чем же придется иметь дело. Первым делом идем в точку входа — index.php в корне нашего сайтика
Я убежден, что логика, представления и данные в Битриксе разделены самым разумным для задач CMS образом.
В этот самый момент я полюбил шаблонизаторы
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 |
<? require($_SERVER["DOCUMENT_ROOT"]."/bitrix/header.php"); $APPLICATION->SetTitle("Интернет-магазин \"Одежда\""); ?> <h2>Лучшие коллекции</h2> <?$APPLICATION->IncludeComponent("bitrix:catalog.top", "", array( "IBLOCK_TYPE_ID" => "catalog", "IBLOCK_ID" => "2", "ELEMENT_SORT_FIELD" => "name", "ELEMENT_SORT_ORDER" => "asc", "ELEMENT_SORT_FIELD2" => "name", "ELEMENT_SORT_ORDER2" => "asc", "HIDE_NOT_AVAILABLE" => "N", "ELEMENT_COUNT" => "8", "LINE_ELEMENT_COUNT" => "4", "PROPERTY_CODE" => array(0=>"MINIMUM_PRICE",1=>"MAXIMUM_PRICE",2=>"",), "OFFERS_FIELD_CODE" => array(0=>"NAME",1=>"",), "OFFERS_PROPERTY_CODE" => array(0=>"ARTNUMBER",1=>"COLOR_REF",2=>"SIZES_SHOES",3=>"SIZES_CLOTHES",4=>"MORE_PHOTO",5=>"",), "OFFERS_SORT_FIELD" => "sort", "OFFERS_SORT_ORDER" => "asc", "OFFERS_SORT_FIELD2" => "id", "OFFERS_SORT_ORDER2" => "desc", "OFFERS_LIMIT" => "0", "VIEW_MODE" => "SLIDER", "TEMPLATE_THEME" => "site", "PRODUCT_DISPLAY_MODE" => "Y", "ADD_PICT_PROP" => "MORE_PHOTO", "LABEL_PROP" => "NEWPRODUCT", "OFFER_ADD_PICT_PROP" => "MORE_PHOTO", "OFFER_TREE_PROPS" => array(0=>"COLOR_REF",1=>"SIZES_SHOES",2=>"SIZES_CLOTHES",), "SHOW_DISCOUNT_PERCENT" => "Y", "SHOW_OLD_PRICE" => "Y", "ROTATE_TIMER" => "30", "MESS_BTN_BUY" => "Купить", "MESS_BTN_ADD_TO_BASKET" => "В корзину", "MESS_BTN_DETAIL" => "Подробнее", "MESS_NOT_AVAILABLE" => "Нет в наличии", "SECTION_URL" => "", "DETAIL_URL" => "", "BASKET_URL" => "/personal/cart/", "ACTION_VARIABLE" => "action", "PRODUCT_ID_VARIABLE" => "id_slider", "PRODUCT_QUANTITY_VARIABLE" => "quantity", "PRODUCT_PROPS_VARIABLE" => "prop", "SECTION_ID_VARIABLE" => "SECTION_ID", "CACHE_TYPE" => "A", "CACHE_TIME" => "180", "CACHE_GROUPS" => "Y", "DISPLAY_COMPARE" => "N", "PRICE_CODE" => array(0=>"BASE",), "USE_PRICE_COUNT" => "N", "SHOW_PRICE_COUNT" => "1", "PRICE_VAT_INCLUDE" => "Y", "PRODUCT_PROPERTIES" => array(), "USE_PRODUCT_QUANTITY" => "Y", "CONVERT_CURRENCY" => "N", "OFFERS_CART_PROPERTIES" => array(0=>"ARTNUMBER",1=>"COLOR_REF",2=>"SIZES_SHOES",3=>"SIZES_CLOTHES",) ), false );?> <h2>Тренды сезона</h2> <?$APPLICATION->IncludeComponent( "bitrix:catalog.top", "", Array( "IBLOCK_TYPE" => "catalog", "IBLOCK_ID" => "2", "VIEW_MODE" => "SECTION", "TEMPLATE_THEME" => "site", "PRODUCT_DISPLAY_MODE" => "Y", "ADD_PICT_PROP" => "MORE_PHOTO", "LABEL_PROP" => "NEWPRODUCT", "OFFER_ADD_PICT_PROP" => "MORE_PHOTO", "OFFER_TREE_PROPS" => array("COLOR_REF", "SIZES_SHOES", "SIZES_CLOTHES"), "SHOW_DISCOUNT_PERCENT" => "Y", "SHOW_OLD_PRICE" => "Y", "MESS_BTN_BUY" => "Купить", "MESS_BTN_ADD_TO_BASKET" => "В корзину", "MESS_BTN_DETAIL" => "Подробнее", "MESS_NOT_AVAILABLE" => "Нет в наличии", "ELEMENT_SORT_FIELD" => "sort", "ELEMENT_SORT_ORDER" => "asc", "ELEMENT_SORT_FIELD2" => "name", "ELEMENT_SORT_ORDER2" => "asc", "SECTION_URL" => "", "DETAIL_URL" => "", "BASKET_URL" => "/personal/cart/", "ACTION_VARIABLE" => "action", "PRODUCT_ID_VARIABLE" => "id_section", "PRODUCT_QUANTITY_VARIABLE" => "quantity", "PRODUCT_PROPS_VARIABLE" => "prop", "SECTION_ID_VARIABLE" => "SECTION_ID", "DISPLAY_COMPARE" => "N", "ELEMENT_COUNT" => "12", "LINE_ELEMENT_COUNT" => "4", "PROPERTY_CODE" => array("MINIMUM_PRICE", "MAXIMUM_PRICE"), "OFFERS_FIELD_CODE" => array("NAME"), "OFFERS_PROPERTY_CODE" => array("ARTNUMBER", "COLOR_REF", "SIZES_SHOES", "SIZES_CLOTHES", "MORE_PHOTO"), "OFFERS_SORT_FIELD" => "sort", "OFFERS_SORT_ORDER" => "asc", "OFFERS_SORT_FIELD2" => "id", "OFFERS_SORT_ORDER2" => "desc", "OFFERS_LIMIT" => "0", "PRICE_CODE" => array("BASE"), "USE_PRICE_COUNT" => "N", "SHOW_PRICE_COUNT" => "1", "PRICE_VAT_INCLUDE" => "Y", "PRODUCT_PROPERTIES" => array(), "USE_PRODUCT_QUANTITY" => "Y", "CACHE_TYPE" => "A", "CACHE_TIME" => "180", "CACHE_GROUPS" => "Y", "HIDE_NOT_AVAILABLE" => "N", "CONVERT_CURRENCY" => "N", "OFFERS_CART_PROPERTIES" => array("ARTNUMBER", "COLOR_REF", "SIZES_SHOES", "SIZES_CLOTHES") ) );?> <?$APPLICATION->IncludeComponent("bitrix:sale.bestsellers", ".default", array( "HIDE_NOT_AVAILABLE" => "N", "SHOW_DISCOUNT_PERCENT" => "Y", "PRODUCT_SUBSCRIPTION" => "Y", "SHOW_NAME" => "Y", "SHOW_IMAGE" => "Y", "MESS_BTN_BUY" => "Купить", "MESS_BTN_DETAIL" => "Подробнее", "MESS_NOT_AVAILABLE" => "Нет в наличии", "MESS_BTN_SUBSCRIBE" => "Подписаться", "PAGE_ELEMENT_COUNT" => "4", "LINE_ELEMENT_COUNT" => "4", "TEMPLATE_THEME" => "site", "DETAIL_URL" => "", "AJAX_MODE" => "N", "AJAX_OPTION_JUMP" => "N", "AJAX_OPTION_STYLE" => "Y", "AJAX_OPTION_HISTORY" => "N", "CACHE_TYPE" => "A", "CACHE_TIME" => "86400", "BY" => "AMOUNT", "PERIOD" => "30", "FILTER" => array( 0 => "CANCELED", 1 => "ALLOW_DELIVERY", 2 => "PAYED", 3 => "DEDUCTED", 4 => "N", 5 => "P", 6 => "F", ), "DISPLAY_COMPARE" => "N", "SHOW_OLD_PRICE" => "N", "PRICE_CODE" => array( 0 => "BASE", ), "SHOW_PRICE_COUNT" => "1", "PRICE_VAT_INCLUDE" => "Y", "CONVERT_CURRENCY" => "N", "BASKET_URL" => "/personal/cart/", "ACTION_VARIABLE" => "action", "PRODUCT_ID_VARIABLE" => "id", "PRODUCT_QUANTITY_VARIABLE" => "quantity", "ADD_PROPERTIES_TO_BASKET" => "Y", "PRODUCT_PROPS_VARIABLE" => "prop", "PARTIAL_PRODUCT_PROPERTIES" => "N", "USE_PRODUCT_QUANTITY" => "N", "SHOW_PRODUCTS_2" => "Y", "CART_PROPERTIES_2" => array( 0 => "BRAND_REF", 1 => "NEWPRODUCT", 2 => "SALELEADER", 3 => "", ), "ADDITIONAL_PICT_PROP_2" => "MORE_PHOTO", "LABEL_PROP_2" => "SALELEADER", "CART_PROPERTIES_3" => array( 0 => "COLOR_REF", 1 => "SIZES_SHOES", 2 => "SIZES_CLOTHES", 3 => "", ), "ADDITIONAL_PICT_PROP_3" => "MORE_PHOTO", "OFFER_TREE_PROPS_3" => array( 0 => "COLOR_REF", 1 => "SIZES_SHOES", 2 => "SIZES_CLOTHES", ), "AJAX_OPTION_ADDITIONAL" => "" ) );?> <?require($_SERVER["DOCUMENT_ROOT"]."/bitrix/footer.php");?> |
Ну да, все понятно, логично и отделено. И да, верстка не смешана с кодом, а короткие теги — это тоже кошерно и современно. Давайте копнем немного глубже и посмотрим, что происходит в их хваленом фреймворке:
Начало неплохое
1 2 3 4 5 6 7 8 9 10 11 |
<? use Bitrix\Main\Loader; use Bitrix\Main\Localization\Loc; use Bitrix\Main\Config\Option; Loc::loadMessages(__FILE__); class CCatalogAdmin { //много чего еще } |
Немного дальше:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
function get_sections_menu($IBLOCK_TYPE_ID, $IBLOCK_ID, $DEPTH_LEVEL, $SECTION_ID, $arSectionsChain = false) { global $adminMenu; //глобальные переменные - это плохо //давайте еще чуток глянем function OnBuildSaleMenu(&$arGlobalMenu, &$arModuleMenu) { if (defined("BX_CATALOG_UNINSTALLED")) return; global $USER; //Нужно больше констант и глобальных переменных |
Для справки — смесь namespace и глобальных переменных — почти по всех файлах ядра. Так же полно абсолютно бесполезных методов для получения переменных из $_SERVER
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 |
//одно из немногих мест ядра с комментариями /** * Returns server document root. * * @return string | null */ public function getDocumentRoot() { return $this->get("DOCUMENT_ROOT"); } /** * Returns custom root folder. * Server variable BX_PERSONAL_ROOT is used. If empty - returns /bitrix. * * @return string | null */ public function getPersonalRoot() { $r = $this->get("BX_PERSONAL_ROOT"); if ($r == null || $r == "") $r = "/bitrix"; return $r; } /** * Returns server http host. * * @return string | null */ public function getHttpHost() { return $this->get("HTTP_HOST"); } /** * Returns server name. * * @return string | null */ public function getServerName() { return $this->get("SERVER_NAME"); } /** * Returns server address. * * @return string | null */ public function getServerAddr() { return $this->get("SERVER_ADDR"); } /** * Returns server port. * * @return string | null */ public function getServerPort() { return $this->get("SERVER_PORT"); } /** * Returns requested uri. * /index.php/test1/test2?login=yes&back_url_admin=/ * * @return string | null */ public function getRequestUri() { return $this->get("REQUEST_URI"); } |
Вопрос — почему тогда в index.php в корне сайта используется
1 |
require($_SERVER["DOCUMENT_ROOT"] |
И в чем тогда смысл плодить непонятные сущности, которые только замедлят обработку и не сделают ничего полезного. В общем странно
Стадия 3 — Использование демо-версии с готовым интернет-магазином
Давайте отвлечемся от неоптимального кода и немного поиспользуем сам магазин. Надо сказать, что режим правки в принципе удобен, но какой ценой — мы правим файлы, а не записи в базе данных. Возьмем раздел «О нас» (в корне сайта папка about).
Что очень огорчило — в бесплатном WordPress меню мы создаем в админке перетаскиванием, это очень удобно. Но в битриксе ценой 25000 рублей, мы вписываем пункты меню вручную.
Скорось битрикса — это отдельный разговор. В то время как все проекты на локальном веб-сервере не вызывают у меня нагрузки как таковой, и время генерации страниц редко превосходит 0,1 секунды без использования кэша, битрикс умудряется генерировать страницы в районе 2-6 секунд. Все происходит из-за того, что собственно все основано на инфоблоках. Т.е. мы создаем к примеру новость с определенными свойствами и т.д., и получаем структуру правильную с точки зрения теории баз данных. Вроде бы все хорошо, только при использовании такой структуры инфоблоков и хранения элементов инфоблоков в одной таблице, так же как и их свойств, мы получаем на выходе такую кашу на sql-сервере:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 |
SELECT BP.* FROM b_iblock_property BP, b_iblock B WHERE BP.IBLOCK_ID=B.ID AND B.ID IN (23) AND UPPER(BP.CODE)=UPPER('COMPANY') SELECT BP.* FROM b_iblock_property BP, b_iblock B WHERE BP.IBLOCK_ID=B.ID AND B.ID IN (23) AND UPPER(BP.CODE)=UPPER('EXPERIENCE') SELECT BP.* FROM b_iblock_property BP, b_iblock B WHERE BP.IBLOCK_ID=B.ID AND B.ID IN (23) AND UPPER(BP.CODE)=UPPER('BRANCH') SELECT BE.ID AS ID, FPV0.VALUE AS PROPERTY_COMPANY_VALUE, FPV0.ID AS PROPERTY_COMPANY_VALUE_ID, FPEN0.VALUE AS PROPERTY_EXPERIENCE_VALUE, FPEN0.ID AS PROPERTY_EXPERIENCE_ENUM_ID, FPV1.ID AS PROPERTY_EXPERIENCE_VALUE_ID,IF(EXTRACT(HOUR_SECOND FROM BE.ACTIVE_FROM)>0, DATE_FORMAT(BE.ACTIVE_FROM, '%d.%m.%Y %H:%i:%s'), DATE_FORMAT(BE.ACTIVE_FROM, '%d.%m.%Y')) AS DATE_ACTIVE_FROM,IF(EXTRACT(HOUR_SECOND FROM BE.ACTIVE_FROM)>0, DATE_FORMAT(BE.ACTIVE_FROM, '%d.%m.%Y %H:%i:%s'), DATE_FORMAT(BE.ACTIVE_FROM, '%d.%m.%Y')) AS ACTIVE_FROM FROM b_iblock B INNER JOIN b_lang L ON B.LID=L.LID INNER JOIN b_iblock_element BE ON BE.IBLOCK_ID = B.ID INNER JOIN b_iblock_property FP0 ON FP0.IBLOCK_ID = B.ID AND FP0.CODE='COMPANY' LEFT JOIN b_iblock_property FP1 ON FP1.IBLOCK_ID = B.ID AND FP1.CODE='EXPERIENCE' LEFT JOIN b_iblock_property FP2 ON FP2.IBLOCK_ID = B.ID AND FP2.CODE='BRANCH' INNER JOIN b_iblock_element_property FPV0 ON FPV0.IBLOCK_PROPERTY_ID = FP0.ID AND FPV0.IBLOCK_ELEMENT_ID = BE.ID LEFT JOIN b_iblock_element_property FPV1 ON FPV1.IBLOCK_PROPERTY_ID = FP1.ID AND FPV1.IBLOCK_ELEMENT_ID = BE.ID LEFT JOIN b_iblock_element_property FPV2 ON FPV2.IBLOCK_PROPERTY_ID = FP2.ID AND FPV2.IBLOCK_ELEMENT_ID = BE.ID LEFT JOIN b_iblock_property_enum FPEN0 ON FPEN0.PROPERTY_ID = FP0.ID AND FPV1.VALUE_ENUM = FPEN0.ID WHERE 1=1 AND ( ((((BE.IBLOCK_ID = '23')))) AND ((((BE.ACTIVE='Y')))) AND ((((FPV0.VALUE_NUM = '373')))) AND ((( FPV2.VALUE_NUM IS NULL OR NOT (FPV2.VALUE_NUM = '317')))) ) AND (((BE.WF_STATUS_ID=1 AND BE.WF_PARENT_ELEMENT_ID IS NULL))) ORDER BY BE.ACTIVE_FROM ASC |
Счетчик просмотров лежит в одной таблице с записями, что убивает возможность кеширования запросов без допиливания напильником.
Итоги моего первого впечатления от Битрикса — CMS с прекрасными маркетологами и не очень внятными разработчиками. Качество кода и скорость его выполнения на веб-сервере, который не настраивали специально под данную cms, мягко говоря плохи. Пока я не увидел серьезных причин написания проекта на данной платформе, а не на Symfony к примеру или в случае интернет-магазина, на OpenCart.
Интерфейс админки симпатичен, но в нем пугающе много всего, назвать его интуитивным язык не повернется. Я думал, что шаблон переназначить можно здесь:
Но нет, оказывается шаблон применяется в настройках сайта:
В дальнейшем я еще расскажу о подводных камнях данной системы. Пока что могу сказать, что если вы начинаете свой путь в веб-разработке, то держитесь подальше от этой системы, дабы не застрять и не привыкнуть к инфоблокам, покупке чужих решений и ступору в развитии. Но если же вы менеджер, которому сказали сделать сайт, и вы не доверяете бесплатным CMS и вообще не знаете что это такое, то удачи.
А вот лично у меня нет желания работать с системой, которую пишут в разных стилях, которая дико тормозит и требует правки конфигов в тех местах, где все остальное летает. А еще хваленая защита битрикса ломается за 5 минут, что вы можете увидеть в начале статьи в виде скриншота админки. Так что удачи в работе с нормальными системами, а я ушел натягивать верстку на это чудище
Теги: битрикс говнокод ненависть
Добавить комментарий
Для отправки комментария вам необходимо авторизоваться.