С моей точки зрения это странно, ведь фильтр обычно полностью определяется URL и не зависит от данных сессии, как, например, корзина.Логика отключения Битрикс - фильтр может порождать большое количество страниц, что может потребовать много места для кэша.$frame =new \Bitrix\Main\Page\FrameBuffered("smart_filter_frame");
$frame->begin();
....тут вызов компонента bitrix:catalog.smart.filter...
$frame->end(); |
$dynamicArea = new \Bitrix\Main\Page\FrameStatic("my_block_".$id) |
| location / { try_files $uri $uri/ /bitrix/urlrewrite.php$is_args$args; } |
| if ($request_uri ~ ^(.*)/index.(html|php)) { return 301 $1/$is_args$args; } |
| server { listen 80; server_name site.ru; root /var/www/site.ru/; index index.php; location ~ \.php$ { include /etc/nginx/fastcgi_params; fastcgi_pass unix:/var/run/php/php7.0-fpm.sock; fastcgi_index index.php; fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; fastcgi_intercept_errors on; } if ($request_uri ~ ^(.*)/index.(html|php)) { return 301 $1/$is_args$args; } location / { try_files $uri $uri/ /bitrix/urlrewrite.php$is_args$args; } location ~* @.*\.html$ { internal; } } |
| location ~ \.php$ { location ~* /\.\./ { internal; } location ~ /\.[^/]+$ { internal; } location ~* ^/upload/1c_[^/]+/ { internal; } location ~* ^/(bitrix/(cache|images|tmp)|upload)/ { internal; } location ~* ^/bitrix/(footer|header|license_key)\.php$ { internal; } location ~* ^/(bitrix|local)/components/(.*)/(.*)/(class|component)\.php$ { internal; } location ~* ^/(bitrix|local)/(backup|blocks|bx_cloud_upload|local_cache|module|modules|managed_cache|php_interface|public|stack_cache)/ { internal; } include /etc/nginx/fastcgi_params; fastcgi_pass unix:/var/run/php/php7.0-fpm.sock; fastcgi_index index.php; fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; fastcgi_intercept_errors on; } location ~* \.(hg|svn|git|bzr)$ { internal; } location ~* /\.\./ { internal; } location ~* @.*\.html$ { internal; } location / { location ~* ^/(bitrix|local)/(backup|blocks|bx_cloud_upload|local_cache|module|modules|managed_cache|php_interface|public|services|stack_cache)/ { internal; } location ~ /\.[^/]+$ { internal; } location ~* ^/upload/1c_[^/]+/ { internal; } try_files $uri $uri/ /bitrix/urlrewrite.php$is_args$args; } |
| modern_browser_value "modern"; modern_browser msie 10.0; modern_browser unlisted; map "$cookie_BITRIX_SM_LOGIN:$cookie_BITRIX_SM_UIDH:$cookie_BITRIX_SM_CC" $storedAuth { default ""; "~*:*:Y" ""; "~*:*:*" 1; "~*:*:" 1; } map "$request_method:$http_bx_action_type:$cookie_BITRIX_SM_NCC:$http_x_forwarded_scheme:$modern_browser:$storedAuth" $usecache { default "1"; "~GET:::*https*" "1"; "~GET:::*:*:" ""; } |
| set $i "index@"; location / { try_files /bitrix/html_pages/$host$uri$i${args}.html /bitrix/html_pages/$host$uri$i${args}=.html /bitrix/html_pages/$host$uri/$i${args}.html$usecache /bitrix/html_pages/$host$uri/$i${args}=.html$usecache $uri $uri/ /bitrix/urlrewrite.php$is_args$args; } |
| server { listen 80; server_name site.ru; root /var/www/site.ru/; index index.php; location ~ \.php$ { include /etc/nginx/fastcgi_params; fastcgi_pass unix:/var/run/php/php7.0-fpm.sock; fastcgi_index index.php; fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; fastcgi_intercept_errors on; } if ($request_uri ~ ^(.*)/index.(html|php)) { return 301 $1/$is_args$args; } set $i "index@"; location / { try_files /bitrix/html_pages/$host$uri$i${args}.html /bitrix/html_pages/$host$uri$i${args}=.html /bitrix/html_pages/$host$uri/$i${args}.html$usecache /bitrix/html_pages/$host$uri/$i${args}=.html$usecache $uri $uri/ /bitrix/urlrewrite.php$is_args$args; } location ~* @.*\.html$ { internal; } } |
<div id="ulogin_div">
<?
$dynamicArea = new \Bitrix\Main\Page\FrameStatic("ulogin_dynamic");
$dynamicArea->setAssetMode(\Bitrix\Main\Page\AssetMode::STANDARD);
$dynamicArea->setStub("<br>Подождите, идёт загрузка...");
$dynamicArea->setContainerID("ulogin_div");
$dynamicArea->startDynamicArea();
?>
<?
$APPLICATION->IncludeComponent(
"ulogin:auth",
"new",
Array(
"PROVIDERS" => "vkontakte,twitter,google,facebook,yandex",
"COMPONENT_TEMPLATE" => ".default",
"GROUP_ID" => array("5"),
"LOGIN_AS_EMAIL" => "Y",
"SEND_EMAIL" => "Y",
"SOCIAL_LINK" => "Y",
"ULOGINID1" => "ваш_id1",
"ULOGINID2" => "ваш_id2"
), $this
);
?>
<?
$dynamicArea->finishDynamicArea();
?>
</div> |
<sc ript src="//ulogin.ru/js/ulogin.js" onl oad="uLoginOnload()"></sc ript> |
<sc ript>
var ul_script = document.createElement('script');
ul_script.src = "//ulogin.ru/js/ulogin.js"
document.body.appendChild(ul_script);
ul_script.onl oad = uLoginOnload;
</sc ript>
|
| Я уже вижу, как некоторых личностей трясет в конвульсии от того, что кто-то посмел в очередной раз написать сообщение в ленту, да ещё и решить задачу, которая имеется "из коробки". Но, пожалуйста, дочитайте до конца. Данный материал не о том, кто круче, и не о решении проблем. Я предлагаю уравновешенным людям, разного уровня, досуг в виде решения совместных головоломок и практик программирования. Причем, не обязательно в рамках предложенного решения, а во всём, что угодно. Предлагайте. |
Регистрация пользователей через соц. сети решается и .
Но если это кого-то, по какой-то причине не устраивает или хочется иметь большую гибкость, иметь возможность наследования или изменения поведения, то можно попробовать и данную библиотеку, разработанную уже достаточно давно. Но как это часто бывает, выкидывать жалко, да иногда и пригождается.
Привёл код в надлежащий для публикации вид и делюсь с общественностью:
Также, данная библиотека может быть хорошей иллюстрацией, для начинающих разработчиков, использования паттерна проектирования . Паттерн используется для унификации объектов или как в данном случае - протокола OAuth.
Также данная библиотека может быть отличным поводом для контрибуции.
Во-первых, пока имеется только три адаптера: Вконтакте, Facebook и Google. Можно их расширить. Во-вторых, в дистрибутив можно включить готовые компоненты авторизации и мульти привязки, к тому же править код библиотеки для этого не потребуется, все данные она уже возвращает и нужный функционал имеет. Такие компоненты я уже делал и они используются на некоторых проектах, но код имеет большую связанность и подойдёт не всем.
В Битрикс сообществе не очень много инициатив для совместной разработки и OpenSource-проектов, но иногда не хватает общения между разработчиками и обменом опыта. Данный пост и предложенное решение не решает серьезных болей, а в очередной раз нацелен на попытку завязать диалог и поиск дружественных точек соприкосновения.
Однажды мне доводилось немного котрибьютить интересное решение , там и до сих пор имеются открытые ишью и пространства для размышления.
Если и у вас есть такие проекты или идеи для совместного решения, пожалуйста в комментарии!
Bitrix\Sale\OrderHistory::deleteOldAgent("365", "100000"); |
$arDeliveryFields = array( "CODE" => "", "PARENT_ID" => 7, "NAME" => "Доставка на дом", "ACTIVE" => "Y", "DESCRIPTION" => "Россия. Вами свяжется менеджер для уточнения стоимости доставки", "SORT" => 100, "CURRENCY" => "RUB", "PRICE" => 0, "CLASS_NAME" => "\Sale\Handlers\Delivery\SimpleHandler", ); $rsDelivery = \Bitrix\Sale\Delivery\Services\Manager::add($arDeliveryFields); |
$rsLocationRestr = \Bitrix\Sale\Internals\ServiceRestrictionTable::add(array(
"SERVICE_ID" => $iDeliveryId,
"SERVICE_TYPE" => \Bitrix\Sale\Services\Base\RestrictionManager::SERVICE_TYPE_SHIPMENT,
"CLASS_NAME" => '\Bitrix\Sale\Delivery\Restrictions\ByLocation',
"SORT" => 100
));
$obCon = \Bitrix\Main\Application::getConnection();
$obCon->queryExecute('INS ERT IN TO b_sale_delivery2location (DELIVERY_ID, LOCATION_CODE, LOCATION_TYPE)
VALUES ("'.$iDeliveryId.'", "'.$sLocationCode.'", "L");'); |
Небольшое, но удобное для использования Vue.js в bitrix. Решение не подразумевает сборку вообще и подходит для маленьких и средних проектов, и уже показало свою стабильность в продакшн много раз.
Но если вам нужно что-то более специфическое и гибкое, то конечно vue-cli, webpack или bitrix/cli подходит больше, я сам периодически употребляю. Эта статья совсем про другое.
В своём решении я поставил несколько требований:<?php
Dbogdanoff\Bitrix\Vue::includeComponent(['todo-list']);
?>
<div id="app">
<todo-list></todo-list>
</div>
<sc ript>
var mainVueApp = new Vue({
el: '#app'
})
</sc ript>
|
# /local/components-vue/todo-list/template.vue:
<template id="todo-list">
<ol>
<li v-for="todo in todos">
{{ todo.text }}
</li>
</ol>
</template>
<sc ript>
Vue.component('todo-list', {
template: '#todo-list',
data: function () {
return {
todos: [
{text: 'Изучить JavaScript'},
{text: 'Изучить Vue'},
{text: 'Создать что-нибудь классное'}
]
}
}
})
</sc ript>
|
local/ └─ components-vue/ ├─ component-one/ | ├─ .settings.php | ├─ template.vue | ├─ script.js | └─ style.css ├─ component-two/ | └─ template.vue └─ component-three/ └─ script.js |
define('DBOGDANOFF_VUE_PATH', '/components-vue'); // поменяли на корень сайта в /components-vue
|
GitHub: (есть более подробное описание работы)
Пример использования: (хорошие примеры разных типов компонентов)
Страница примера:
use Bitrix\Main\Localization\Loc,
Bitrix\Main\Config\Option,
Bitrix\Sale,
Bitrix\Main\Entity\DataManager;
if(!CModule::IncludeModule('sale'))
return;
$dbSite = CSite::GetByID(WIZARD_SITE_ID);
if($arSite = $dbSite -> Fetch())
$lang = $arSite["LANGUAGE_ID"];
if(strlen($lang) <= 0)
$lang = "ru";
$bRus = false;
if($lang == "ru")
$bRus = true;
$defCurrency = "EUR";
if($lang == "ru")
$defCurrency = "RUB";
elseif($lang == "en")
$defCurrency = "USD";
//*********************** ADD PAYSYSTEM ***********************//
global $APPLICATION;
$paysystem = \Bitrix\Sale\Internals\PaySystemActionTable::add(array(
"CURRENCY" => $defCurrency,
"NAME" => GetMessage("SALE_WIZARD_PAYSYSTEM_CASH_NAME"),
"ACTIVE" => "Y",
"SORT" => 100,
"DESCRIPTION" => GetMessage("SALE_WIZARD_PAYSYSTEM_CASH_DESC"),
));
$paysystem_id = $paysystem->getId();
if($paysystem_id) {
$fields = array(
'PARAMS' => serialize(array('BX_PAY_SYSTEM_ID' => $paysystem_id)),
'ENTITY_REGISTRY_TYPE'=>'ORDER',
'PAY_SYSTEM_ID' => $paysystem_id,
'LOGOTIP' => 930,
'IS_CASH' => 'Y',
'ACTION_FILE' => 'cash',
'HAVE_PAYMENT' => 'Y',
'HAVE_ACTION' => 'N',
'HAVE_RESULT' => 'N',
'HAVE_PREPAY' => 'N',
'HAVE_PRICE' => 'N',
'HAVE_RESULT_RECEIVE' => 'N',
'ALLOW_EDIT_PAYMENT' => 'Y',
'AUTO_CHANGE_1C' => 'N',
'CAN_PRINT_CHECK' => 'N',
'PSA_NAME' => GetMessage("SALE_WIZARD_PAYSYSTEM_CASH_NAME"),
);
$result = Bitrix\Sale\Internals\PaySystemActionTable::update($paysystem_id, $fields);
if(is_object($result)) {
Bitrix\Main\Diag\Debug::writeToFile('Добавлена и обновлена платежная система "' . GetMessage("SALE_WIZARD_PAYSYSTEM_CASH_NAME") . '" #' . $paysystem_id . '');
}else{
Bitrix\Main\Diag\Debug::writeToFile('ERROR: платежная система "' . GetMessage("SALE_WIZARD_PAYSYSTEM_CASH_NAME") . '" #' . $paysystem_id . ' не обновлена!');
Bitrix\Main\Diag\Debug::writeToFile($APPLICATION->LAST_ERROR);
}
}else{
Bitrix\Main\Diag\Debug::writeToFile('ERROR: платежная система "' . GetMessage("SALE_WIZARD_PAYSYSTEM_CASH_NAME") . '" не добавлена!');
Bitrix\Main\Diag\Debug::writeToFile($APPLICATION->LAST_ERROR);
}
//*********************** X ADD PAYSYSTEM ***********************// |
use Bitrix\Main\Page\Asset,
Bitrix\Main\Localization\Loc;
// Получаем содержимое языкового файла
$ARJSMESS = Loc::LoadLanguageFile($_SERVER["DOCUMENT_ROOT"].$templateFolder."/script.js.php");
if (!empty($ARJSMESS)) {
// Добавляем объект с переводами.
Asset::getInstance()->AddString("<sc ript type=\"text/javascript\">BX.message(".CUtil::PhpToJSObject($ARJSMESS).")</sc ript>");
} |
$arParams['CHECK_PRICE'] = (isset($arParams['CHECK_PRICE']) && $arParams['CHECK_PRICE'] == 'N' ? 'N' : 'Y'); |
$arParams['CHECK_PRICE'] = 'N'; |
foreach ($arAllQuestions as $arQuestion)
{
$txt = '';
foreach($arQuestion["ANSWERS"] as $arAnswer)
{
if ($msg = CVoteEvent::GetAnswer($res['ID'], $arAnswer['ID']))
{
if (
($arAnswer['FIELD_TYPE'] < 4) // not a string
&& (intval($msg) > 0)
)
$msg = $arAnswer['MESSAGE'];
$txt .= htmlspecialcharsbx($msg).'<br />';
}
}
$row->AddViewField("Q".$arQuestion["ID"], $txt);
}
|
function GetAnswer($EVENT_ID, $ANSWER_ID)
{
$err_mess = (self::err_mess())."<br>Function: GetAnswer<br>Line: ";
global $DB;
$EVENT_ID = intval($EVENT_ID);
$ANSWER_ID = intval($ANSWER_ID);
$strSql = "
SEL ECT
A.ANSWER_ID,
A.MESSAGE
FR OM
b_vote_event E,
b_vote_event_answer A,
b_vote_event_question Q
WHERE
E.ID = '$EVENT_ID'
and Q.EVENT_ID = E.ID
and A.EVENT_QUESTION_ID = Q.ID
and A.ANSWER_ID = '$ANSWER_ID'
";
$z = $DB->Query($strSql, false, $err_mess.__LINE__);
if ($zr = $z->Fetch())
{
if (strlen($zr["MESSAGE"])>0) return $zr["MESSAGE"]; else return $zr["ANSWER_ID"];
}
return false;
} |
/************** Initial list - Get data ****************************/ $rsData = CVoteEvent::GetList($by, $order, $arFilter, $is_filtered, "Y"); // делаем массив ответов // выборка нужных ответов, одна штука $tmpSql = 'SEL ECT e.ID, a.ANSWER_ID, a.MESSAGE FR OM b_vote_event e LEFT JOIN b_vote_event_question q ON q.event_id = e.id LEFT JOIN b_vote_event_answer a ON a.event_question_id = q.id WH ERE e.vote_id = '.$VOTE_ID.';'; $aRes = $DB->Query($tmpSql); $answers = array(); // массив ответов while ($answer = $aRes->Fetch()) $answers[$answer["ID"]][$answer["ANSWER_ID"]] = $answer["MESSAGE"]; // готово $rsData = new CAdminResult($rsData, $sTableID); $rsData->NavStart(); |
foreach ($arAllQuestions as $arQuestion)
{
$txt = '';
foreach($arQuestion["ANSWERS"] as $arAnswer)
{
$msg = false;
// достаём из массива ответов при наличии, а не ломимся в базу с запросом
if (array_key_exists($arAnswer['ID'], $answers[$arRes['ID']]))
$msg = (strlen($answers[$arRes['ID']][$arAnswer['ID']])>0) ? $answers[$arRes['ID']][$arAnswer['ID']] : $arAnswer['ID'];
if ($msg)
{
if (
($arAnswer['FIELD_TYPE'] < 4) // not a string
&& (intval($msg) > 0)
)
$msg = $arAnswer['MESSAGE'];
$txt .= htmlspecialcharsbx($msg).'<br />';
}
}
$row->AddViewField("Q".$arQuestion["ID"], $txt);
}
|
Запрос № 20: SELECT e.ID, a.ANSWER_ID, a.MESSAGE FR OM b_vote_event e LEFT JOIN b_vote_event_question q ON q.event_id = e.id LEFT JOIN b_vote_event_answer a ON a.event_question_id = q.id WHERE e.vote_id = 32; Время выполнения: 0.01849 сек. |
$arAllQuestions = array();
$rsQuestions = CVoteQuestion::GetList($voteId, $by, $order, array(), $is_filtered);
while ($arQuestion = $rsQuestions->Fetch())
{
$headers[] = array(
"id"=>"Q".$arQuestion["ID"],
"content"=>htmlspecialcharsbx($arQuestion["QUESTION"]),
"sort"=>'',
"default"=>true);
$arAllAnswers = array();
$rsAnswers = CVoteAnswer::GetList($arQuestion["ID"]); // тот же классический отстой с отдельными запросами для получения вариантов ответов по каждому вопросу
while ($arAnswer = $rsAnswers->Fetch())
{
$arAllAnswers[$arAnswer['ID']]=$arAnswer;
}
$arAllQuestions[] = array('ID' => $arQuestion["ID"], 'ANSWERS' => $arAllAnswers);
}
|
$arAllAnswers = array(); // массив вариантов ответов
$rsAnswers = CVoteAnswer::GetListEx(array("s_c_sort" => "ASC"), array("VOTE_ID" => $VOTE_ID)); // тут, по счастью, для выборки есть годный метод api
while ($arAnswer = $rsAnswers->Fetch())
{
$arAllAnswers[$arAnswer['QUESTION_ID']][$arAnswer['ID']]=$arAnswer;
}
$arAllQuestions = array();
$rsQuestions = CVoteQuestion::GetList($VOTE_ID, $by, $order, array(), $is_filtered);
while ($arQuestion = $rsQuestions->Fetch())
{
$headers[] = array(
"id"=>"Q".$arQuestion["ID"],
"content"=>htmlspecialcharsbx(strip_tags($arQuestion["QUESTION"])),
"sort"=>'',
"default"=>true);
// жесть вырезана
$arAllQuestions[] = array('ID' => $arQuestion["ID"]); // массив нужен для правильного порядка вопросов, но оставляем только ID, остальное уже есть в $arAllAnswers
}
|
foreach ($arAllQuestions as $arQuestion)
{
$txt = '';
foreach($arAllAnswers[$arQuestion["ID"]] as $arAnswer) // достаём варианты ответов на вопрос из массива
|