Сниппеты - очень полезная штука
Сомневаюсь что вы не знаете что это такое, но если не поняли, то это когда в js пишешь log, нажимаешь tab, и появляется console.log();
Все ими пользуются, но не все пишут. Так зачем о них говорить? Потому что они куда сильнее добавления нескольких символов.
Например, когда лень в пхп включать дебаг, выводить массив на страницу не очень красиво, а подключать либы для этого не хочется, то можно
jspre разворачивающийся в
?>
<script>
console.log(<?=json_encode($arResult, JSON_PARTIAL_OUTPUT_ON_ERROR)?>);
</script>
<?И вот к вашим услугам просмотр хешмапа в консоли, допустим, хрома со всеми вытекающими. А это и возможность свернуть развернуть и весь js.
Кстати, сниппеты как правило зависят от языка. Значит закрытие этих пхп тегов идет только если нужно. А внутри html этого не надо, ну и внутри js не нужны теги скрипта.
Ну или еще маленький пример:
// ident_array
$arResult = array_combine(
array_column($arResult, "KEY"),
$arResult
);Простенькая фигня делающая значение массива его ключом. В пхп этого не хватает, ну или не хватало, ведь все обновляется и улучшается, так ведь?)
Конечно всякие аяксы из jquery, или axios или даже удобная вам форма fetch.
Но это только сниппеты для языка, а когда нужно что-то для фреймворка, то тут как раз начинается самое приятное. Кривая вывела меня на bitrix, и чтобы не пугать народ примеров будет мало. Но некоторые стоит привести.
// bx_if_me - не делайте так в серьезных местах, но все же.
if ($USER->GetLogin() === "Тут мой логин") {
#CODE
}
// bx_prolog - эту фигню считается хорошим тоном (да) ставить почти во всех пхп файлах
if (!defined('B_PROLOG_INCLUDED') || B_PROLOG_INCLUDED !== true) {
die();
}
// bx_includeModule - нужно очень часто, и хорошо бы переписать на новый стиль вместо CModule
/* зато повод сказать что в сниппетах есть возможность прописывать варианты по умолчанию а в некотоых IDE (sublime, vim) можно даже вставлять набор переводов в зависимости от выбранного значения */
if(!CModule::IncludeModule("${1|iblock,highloadblock,catalog,sale,pull,моя_компания.мой_модуль|}")) {
ShowError("Модуль ${1} не установлен!");
return;
}
// d7_iblockElementQuery - Вообще конкретно этой фигней пока пользоваться не стоит, но все юзают, так что развлекайтесь и вы
/* Кстати если все виснет, то вероятно xDebug ушел в бесконечную рекурсию */
$items = \Bitrix\Iblock\Elements\ElementCatalogTable::query() // гуглить bitrix orm инфоблоки
->setSelect([
"ID",
"ALIAS" => "PROPERTY_CODE.VALUE",
])
->where("ID", "in", $arrayWithIds)
->setLimit(20)
->exec()->fetchAll();
// d7_file_reference - И все, теперь у модели будут и ссылка на модель файла и строка с src
/* это вставляется в getMap в описании модели в модуле. Просто элементы массива
Полные пути как раз потому что сниппет, но можно все выносить в use, я не против.
*/
(new \Bitrix\Main\ORM\Fields\Relations\Reference(
"FILE",
\Bitrix\Main\FileTable::class,
\Bitrix\Main\ORM\Query\Join::on('this.UF_FILE', 'ref.ID')
))->configureJoinType('left'),
(new \Bitrix\Main\ORM\Fields\ExpressionField(
'FILE_SRC',
"CONCAT('/upload/', %s, '/', %s)",
array('FILE.SUBDIR', 'FILE.FILE_NAME')
)),Ну и понятно для стандартных вещей старого ядра весь CRUD сделан сниппетами, с комментариями где тут фильтр, а где сортировка. Ну и для разделов на d7 тоже сниппет. Или чтобы вставить включаемую область - сниппет. Или подключить самописный компонент обратной связи. Или меню. Ресайз картинки, ссылочное поле в d7 query, логику Or туда же. В общем статьи не хватит чтобы охватить все сокращенные нажатия на кнопочки.
А еще можно закидывать в сниппеты стандартные костыли:
// bx_ob
/*
Один из старых способов держать некешируемое в кешируемом через замену вида
SOME_PREFIX_123 на что-то
Сам сниппет содержит код для трех файлов, по которым его еще надо разнести
В общем костыль тот еще, но искать его в тех редких моментах, когда он нужен еще хуже.
*/
// Это идет в шаблон
ob_start();
$component->arResult["CACHED_TPL"] = ob_get_clean();
// Далее код для других файлов, который обычно выделен если сниппет правильно написан,
// чтобы удалить его одним del и просто использовать обычный ob
// в файл result_modifier
$this->__component->arResultCacheKeys = array_merge(
$this->__component->arResultCacheKeys,
['CACHED_TPL']
);
// в файл component_epilog
$arResult["CACHED_TPL"] = preg_replace_callback(
"/#SOME_PREFIX_([\d]+)#/is".BX_UTF_PCRE_MODIFIER,
function ($matches){
ob_start();
global $APPLICATION;
// тут что-то использующее $matches и некешируемое,
// только не надо запросы в базу, это ведь цикл ;)
$returnStr = ob_get_clean();
return $returnStr;
},
$arResult["CACHED_TPL"]
);
// Это все снова идет в шаблон
echo $this->__component->arResult["CACHED_TPL"];
// Это все был один сниппет
//------------------------------------------------------------------------
// bx_ciblock_cache
/* Если в компонент пихать не хочется, а кеш на инфоблоках все же нужен.
Понятно что в сниппете расставлены места для правки, такие как cache_dir, iblock_id
*/
$obCache = new CPHPCache();
if ($obCache->InitCache(36000, "", "/iblock/cache_dir")) {
$arResult = $obCache->GetVars();
} elseif ($obCache->StartDataCache()) {
\Bitrix\Main\Loader::includeModule('iblock');
if (defined("BX_COMP_MANAGED_CACHE")) {
global $CACHE_MANAGER;
$CACHE_MANAGER->StartTagCache("/iblock/cache_dir");
$CACHE_MANAGER->RegisterTag("iblock_id_" . iblock_id);
}
$arResult = [];
# Весь код тут и задает переменную $arResult, которая будет браться из кеша
if (defined("BX_COMP_MANAGED_CACHE")) {
$CACHE_MANAGER->EndTagCache();
}
$obCache->EndDataCache($arResult);
}Плагины это как сниппеты, но лучше
Написание плагинов тратит кучу времени, да еще делается на незнакомом языке. Обычно из-за этого интересней, но если нет, вайб-кодинг в помощь.
В том же битриксе система папок и файлов даже в обычном строгом виде напоминает абстрактное искусство. Поэтому себе я писал плагин, открывающий компоненты и шаблоны по названию. Те самые, которые откроет код.
Потом в vscode делал даже меню чтобы открывать их.
Ну и заодно создавать все эти стандартные файлы, раз уж в битриксе нельзя делать просто
bitrix g component someName -component_epilog
Приводить вид всего этого я не буду, ибо в саблайм искать лень, а для всКода я нечаянно стер со всем wsl, и так и не написал заново.
Композер - тоже может расширять каждый проект
Вы ведь пользуетесь локалками? Или вам нужно чтобы кто-то поднял вам дев? Только не говорите что правите все на проде. В общем если вы пользуетесь локалками то
source:
image: alpine:latest # не настаиваю
container_name: ${PROJECT}source
volumes:
# ...
- ${CONFIG_RELATIVE_PATH}/scripts/:/var/www/bitrix/scripts
# ...И в папку со скриптами вставляйте что нужно.
Например скрипт добавления вашего пользователя, авторизации под ним. Управления его группами.
А еще я туда запихнул для битрикса запекание моделей хайлоадов, но это что-то на языке Мордора.
Но если ваш фреймворк можно расширять таким способом, то это упростит жизнь. Сколько раз было, выкачиваешь проект и нужно залогиниться, и увы это не, например, рельсы и нельзя просто rails c и что-то вида users.add("login", "pass"). Точный синтаксис уточняйте в инете.
Но если у вас нету идей чего бы запихнуть в скрипты, то можно подключить несколько образов. Например
adminer: # ну или phpMyAdmin
image: adminer
container_name: ${PROJECT}adminer
links:
- db:db
ports:
- '${INTERFACE}:8080:8080'
networks:
- bitrix
# перехват почты, очень помогает в отладке писем,
# кстати можно ставить e2e тесты на письма
mailhog:
image: mailhog/mailhog
container_name: ${PROJECT}mailhog
logging:
driver: 'none' # disable saving logs
networks:
- bitrix
ports:
- '${INTERFACE}:1025:1025' # smtp server
- '${INTERFACE}:8025:8025' # web ui
restart: on-failureКонсоль - вообще огонь
Вам не поставили миграции?
function mysqlLoad {
if [ "$REMOTE_TYPE" = "docker" ]; then
ssh -C $PROD_SSH " cd $PROD_PATH && cd .. && docker-compose exec -T db mysqldump \"--no-tablespaces\" \"-u\" \"$MYSQL_USER\" \"-p$MYSQL_PASSWORD\" \"$MYSQL_DATABASE\" | gzip -c" | pv | gunzip | docker exec -i $PROJECT"db" "mysql" "-u$MYSQL_USER" "-p$MYSQL_PASSWORD" $MYSQL_DATABASE
else
ssh -C $PROD_SSH " mysqldump --no-tablespaces -u $MYSQL_USER -p$MYSQL_PASSWORD $MYSQL_DATABASE | gzip -c" | pv | gunzip | docker exec -i $PROJECT"db" "mysql" "-u$MYSQL_USER" "-p${MYSQL_PASSWORD//\\/}" $MYSQL_DATABASE
fi
}Окей, понимаю страшно. Начнем попроще.
Начнем с просто backward. Или нет, рано нам еще с этого начинать, надо начать с rsync. Если вы пользуетесь гитом для выкачивания и закачивания кода, то вы наверное не прогаете на битриксе) У нас увы файлы могут редактировать люди, для которых божественные знаки G-+ (git) ничего не говорят. А затирать их правки - потом ругаться. Так что rsync поможет выкачать проект, без картинок, без кеша, без бекапа.
rsync --no-inc-recursive --info=progress2 -rza --exclude="cache" --exclude="managed_cache" --exclude="backup" "$PROD_SSH:$PROD_PATH" .Быстро, и приятно с привычкой. Хотя бы для создания локалок.
К этому моменту меня перестали читать, но если кто-то все же прошелся по диагонали, то заметил что в моих консольных командах целая куча переменных.
Что же) Ежедневная функция oprj (open project)
function oprj {
local files
if [[ $1 ]]; then
files="$1"
else
files=$(ls /mnt/g/work | fzf)
fi
if [ -n "$files" ]; then
export BASE_DIR=/mnt/g/work/"$files"
if [ -d /mnt/g/work/"$files"/site ]; then
export SITE_DIR=/mnt/g/work/"$files"/site/
else
export SITE_DIR=/mnt/g/work/"$files"/ln/
fi
cd $SITE_DIR
fi
export WDIR="/mnt/g/work/$files/"
if [ -f "$BASE_DIR/.env" ]; then
echo "exporting vars from .env"
# source "$BASE_DIR/.env"
export MYSQL_USER=$(grep '^[\s\t]*MYSQL_USER=' "$BASE_DIR/.env" | awk -F '=' '{printf $2}' | tr -d '\r')
export MYSQL_PASSWORD=$(grep '^[\s\t]*MYSQL_PASSWORD=' "$BASE_DIR/.env" | awk -F '=' '{printf $2}' | tr -d '\r')
export MYSQL_DATABASE=$(grep '^[\s\t]*MYSQL_DATABASE=' "$BASE_DIR/.env" | awk -F '=' '{printf $2}' | tr -d '\r')
export PROJECT=$(grep '^[\s\t]*PROJECT=' "$BASE_DIR/.env" | awk -F '=' '{printf $2}' | tr -d '\r')
export REMOTE_TYPE=$(grep '^[\s\t]*REMOTE_TYPE=' "$BASE_DIR/.env" | awk -F '=' '{printf $2}' | tr -d '\r')
export SITE_IP=$(grep '^[\s\t]*INTERFACE=' "$BASE_DIR/.env" | awk -F '=' '{printf $2}' | tr -d '\r')
export PROD_PATH=$(cat "$BASE_DIR/remote_path" | sed -e 's/\(.*\):\(.*\)/\2/')
export PROD_SSH=$(cat "$BASE_DIR/remote_path" | sed -e 's/\(.*\):.*/\1/') && \
export PROD_SSH_USER=$(echo $PROD_SSH | sed -e "s/\(.*\)@.*/\1/") && \
export PROD_SSH_HOST=$(echo $PROD_SSH | sed -e "s/.*@\(.*\)/\1/")
fi
echo "Opened $PROJECT prod on $PROD_SSH:$PROD_PATH"
echo "local image is http://$SITE_IP/"
}Думаю есть какой-то куда более простой и правильный способ собирать переменные из .env файла. Но такие штуки пишутся сначала для себя. И нейросеток тогда еще не было. В общем код показываю, а не говорю про него, и знаю как он пахнет.
Эта функция, который я пользовался минимум каждый рабочий день. Просто чтобы открыть последний проект.
oprj projectName # открыть проект
backward # обертка для rsync чтобы скачать файлы
mysqlLoad # скачать базу
dockerUp # да я сделал обертку для поднятия композера, чтобы мочь управлять докером не переходя в нужные папки
code . # запустить редактор кода А что если вы на винде? Ну тут есть wsl. Правда с докером он дружит как кошка с собакой.
Поэтому в баше после каждой перезагрузки powershell.exe -ExecutionPolicy Bypass -f f:/winscripts/docker_wsl_11.ps1 ну а в скрипте
isAdmin = ([Security.Principal.WindowsPrincipal] [Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole([Security.Principal.WindowsBuiltInRole]::Administrator)
if (-not $isAdmin) {
# Перезапуск с правами администратора
Start-Process powershell -Verb RunAs -ArgumentList "-ExecutionPolicy Bypass -File `"$PSCommandPath`""
Exit
}
$job1 = Start-Job { netsh interface ip add address "vEthernet (WSL)" 192.168.50.88 255.255.255.0 }
Wait-Job $job1
Receive-Job $job1
Start-Sleep -s 1
$job2 = Start-Job { wsl -d ubuntu_work -u root -- service docker start}
Wait-Job $job2
Receive-Job $job2
Start-Sleep -s 1
$job4 = Start-Job { wsl -d ubuntu_work -u root -- ip addr add 192.168.50.16/24 broadcast 192.168.50.255 dev eth0 label eth0:1}
Wait-Job $job4
Receive-Job $job4
$job10 = Start-Job { wsl -d ubuntu_work -u root -- docker ps -q `| xargs docker kill }
Wait-Job $job10
Receive-Job $job10
Start-Sleep -s 1
$job7 = Start-Job { wsl -d ubuntu_work -u root -- iptables -I DOCKER-USER -i src_if -o dst_if -j ACCEPT}
Wait-Job $job7
Receive-Job $job7
Start-Sleep -s 1
$job8 = Start-Job { route add 10.101.0.0/16 192.168.50.16 }
Wait-Job $job8
Receive-Job $job8Любой сколько-то знающий powerShell закидает меня камнями, поэтому опишу промптом:
`Задай сетевой карточке wsl айпишник (всегда одинаковый, например для xDebug). Запусти докер внутри линукса, но прибей все контейнеры. Ну и тоже пропиши айпишник и подсеть сетевой карточке, но уже внутри wsl. Дай внешний доступ к докеру внутри wsl. И если я иду на 10.101.***.*** то значит я хочу в докер внутри моего wsl. Все делай по очереди с паузами в секунду между командами.`
После этого останется задавать проектам подсетки вида "проект 1 => 10.101.1.*", "проект 2 => 10.101.2.*"
И даже можно сделать так, чтобы какой-то проект светил в инет, но тут уже аккуратней, локалки все же, со скриптами автологина под админом.
Бонус - мощь sublime-keymap
Увы и ах, но такого я в других местах не встречал. А фишка тут в возможности выполнения макросов по кнопке, по матчам регулярок.
[
//...
// Выдели true или false и нажми ! и оно поменяется на противоположное.
{ "keys": ["!"], "command": "insert", "args": {"characters": "false"}, "context":[
{"key": "text", "operator": "regex_match", "operand": "true", "match_all": true},
{"key": "setting.command_mode", "operand": false}
]},
{ "keys": ["!"], "command": "insert", "args": {"characters": "true"}, "context":[
{"key": "text", "operator": "regex_match", "operand": "false", "match_all": true},
{"key": "setting.command_mode", "operand": false}
]},
// помните <a href="javascript:void(0)">...</a>
// так вот, можно сделать так чтобы после первой j он сам появлялся
{ "keys": ["j"], "command": "insert", "args": {"characters": "javascript:void(0)"}, "context":[
{"key": "preceding_text", "operator": "regex_match", "operand": ".*href[\\s]*=[\\s]*[\"|']"},
{"key": "setting.command_mode", "operand": false}
]},
// Тут использовались макросы, а суть открывать пхп по "?"
// Ну и быстрый <?= курсор тут ?> по "="
// текст макросов приводить не буду, они элементарные.
{ "keys": ["="], "command": "run_macro_file", "args": {"file": "res://Packages/User/macro/php/quick_echo_php.sublime-macro"}, "context":[
{"key": "selector", "operator": "equal", "operand": "embedding.php", "match_all":true},
{"key": "selector", "operator": "not_equal", "operand": "meta.embedded.line.php", "match_all":true},
{"key": "selector", "operator": "not_equal", "operand": "source.php", "match_all":true},
{"key": "selector", "operator": "not_equal", "operand": "source.js.embedded.html", "match_all":true},
{"key": "selector", "operator": "not_equal", "operand": "punctuation.definition.tag.end.html", "match_all":true},
{"key": "preceding_text", "operator": "not_regex_match", "operand": ".*<"},
{"key": "preceding_text", "operator": "not_regex_match", "operand": ".*\\?"},
{"key": "preceding_text", "operator": "not_regex_match", "operand": ".*[a-zA-Zа-яА-Я]+"},
{"key": "setting.command_mode", "operand": false}
]},
{ "keys": ["?"], "command": "run_macro_file", "args": {"file": "res://Packages/User/macro/php/quick_php.sublime-macro"}, "context":[
{"key": "selector", "operator": "equal", "operand": "embedding.php", "match_all":true},
{"key": "selector", "operator": "not_equal", "operand": "meta.embedded.line.php", "match_all":true},
{"key": "selector", "operator": "not_equal", "operand": "source.php", "match_all":true},
{"key": "selector", "operator": "not_equal", "operand": "source.js.embedded.html", "match_all":true},
{"key": "preceding_text", "operator": "not_regex_match", "operand": ".*<"},
{"key": "preceding_text", "operator": "not_regex_match", "operand": ".*\\?"},
{"key": "setting.command_mode", "operand": false}
]},
// ...
]Эпилог
Это все древние технологии до нейросетей. Но они экономили мне кучу времени и нервов. В общем виде они к битриксу не имеет отношения. Все это появлялось от нежелания делать одно и то же. Будь то написание подключения хедера для нового файла, поиск файла шаблона, авторизации или синхронизация базы.
Когда ловите себя на прокрастинации перед повторением одной и той же фигни - автоматизируйте ее. Это проще чем кажется, да и весело.
