Сниппеты - очень полезная штука
Сомневаюсь что вы не знаете что это такое, но если не поняли, то это когда в 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} ]}, // ... ]
Эпилог
Это все древние технологии до нейросетей. Но они экономили мне кучу времени и нервов. В общем виде они к битриксу не имеет отношения. Все это появлялось от нежелания делать одно и то же. Будь то написание подключения хедера для нового файла, поиск файла шаблона, авторизации или синхронизация базы.
Когда ловите себя на прокрастинации перед повторением одной и той же фигни - автоматизируйте ее. Это проще чем кажется, да и вес��ло.
