Александр Туниеков

Александр Туниеков

С нами с 19 декабря 2015; Место в рейтинге пользователей: #15
Александр Туниеков
2 часа назад
0
ну тогда groupby и having
«query» принимает все параметры pdoFetch и в нем есть и groupby и having. Пример навскидку:
"query":{
		"class":"modUser",
		"leftJoin":{
			"modUserProfile":{
				"class":"modUserProfile",
				"on":"modUserProfile.internalKey = modUser.id"
			}
		},
		"select":{
			"modUser":"modUser.id",
			"modUserProfile":"modUserProfile.fullname,modUserProfile.email,modUserProfile.phone"
		},
		"where":{
			"modUser.active":1
		},
                "groupby":"modUser.primary_group",
                "having":{
                    "count(*)  > 3"
                },
		"sortby":{
			"modUser.id":"DESC"
		}
	}
Вроде такой запрос должен работать. «count(*) > 3» не уверен, что правильно составил.
+ подгрузка не родных пакетов
«loadModels»
{
        "actions": {
            "read": [],
            "create": [],
            "update": [],
    	    "delete": []
        },
        "loadModels" :"modextra,gtsshop",
...
еще я правильно понимаю что фильтрация и сортировка по умолчанию по всем полям?
Да правильно.

$object->set('password',md5(date('d.m.Y H:i:s')));
как потом этим пользоваться?
Хм. взял пример из Создание CRUD интерфейса вне админки. Не знаю зачем там случайный пароль ставили. Просто повторил на gtsAPI. Можно добавить поле password в таблицу и можно будет ставить пароль. Но прочитать его нельзя. MODX кеш пароля выдаст.
У нас пароли юзеров храняться в текстовом файле у меня. Так нам удобнее и я думал сделать интерфейс отделу кадров, чтоб они могли поставить и прочитать пароль. То есть сохранить его плагином в extended (Лучше редактировать extended, а password менять плагином). Но пока не до этого и директору может не понравиться.
Кстати extended, то есть JSON поле gtsAPI уже может редактировать.
"fields":{
        "extended.pass":{
            "label":"Пароль",
            "type":"text"
        }
    }
Но типа поля password еще нет. Он мне еще не нужен был.
Как использовать плагины, наверно, не очень понятно. Надо описать триггеры. Думал попозже сделать.
Александр Туниеков
2 часа назад
0
думаю 100мс на инициализацию бекенда это очень много — что-то не так с хостингом, или что-то очень тяжелое прикручено в плагинах на события onmodxinit или где-то ещё по пути до рендеринга
Как-то пробовал разобраться почему так много, но не разобрался. Может потому, что сервер на винде. Надо будет еще пробовать разобраться. В 500мс время реакции приложения укладывается и это не парит. Но загрузка приложения в 1.62 секунды уже не хорошо. Хотя пользователи не ругаются. 1С, например, 2 минуты грузиться и 2 секунды для них не страшно :-).

HTMX встречал упоминания и читал их, но вникать и пробовать использовать еще не думал. UI-фреймворков для него вроде еще нет и пока для меня бесполезно.

Тоже интересно, для чего реально используешь @Александр Туниеков gtsAPI
Описал в ответе Артуру :-)

Не переписываешь ли потихоньку всю админку на формы VUE? ))
Временами подмывает переписать :-). Но в админке используются формы, попапы, таблицы, дерево и файл-менеджер. Дерево и файл-менеджер мне в работе (в нашей ERP) нужны, но их делать месяц два на каждый и пока все время откладывается.
Александр Туниеков
3 часа назад
0
Вот форма с которую сейчас сдаю в работу. Расчет деталей вентиляции

Использую из PrimeVue DataTable, поля форм, Dialog, Tabs, Toast, Popover

И Drawer

Будет еще форма прикрепления документов (Отчет, Счет и т.д.) к расчету.

А PHP многопоточный? Думаю скорость ответа NodeJs не от этого высокая.
На ноде при запуске сервера можно большую часть проинициализировать. Например, прогрузить настройки, чанки и сниппеты в память и не лазить за ними в базу или диск при каждом запросе. Это я пробовал на ноде like MODX сделать, но потом понял, что чанков нет и архитектура js другая и забросил.

А ещё хотелось бы понять для кого и для чего компонент gtsAPI? Какие практические задачи ты с его помощью решаешь?
Основное — это быстро сделать табличный CRUD, а остальное уже подтягивается. CRUD есть и более сложные задачи уже проще используя уже сделанное АПИ делать.
Александр Туниеков
4 часа назад
0
Спасибо за отзыв :-). Написал заметку и подумал, что получилась заметка какой-то странной. Даже думал публиковать или нет. Но интересно что другие думают поэтому опубликовал. Я работаю над проектами один и у меня с обратной связью плохо. Не знаю толи правильно делаю толи можно сделать проще :-(.
Привет не понятно где храниться код который ты добавляешь. И что за код. Рискну предположить, что у тебя обрезается код сниппетов. Сниппеты хранятся в базе и возможно длины поля не хратает под твои огромные сниппеты. По умолчанию в modx_site_snippets тип поля snippet MEDIUMTEXT. По идее для всего должно хватать О_О. Что за код у тебя? Объясни подробнее
А HTML код… В modx_site_content: content и в modx_site_htmlsnippets: snippet тоже MEDIUMTEXT…
Александр Туниеков
14 ноября 2024, 11:50
0
Добрый день! Установил MarkdownEditorFrontend с modstore и xpdo выдало ошибку что не может найти сервис. К моему удивлению в транспортном пакете не нашлось папок assets и core (0 и 1 в modCategory). И, соответственно, они не установились. Перезалейте пожалуйста пакет. Если еще выложете в гитхаб то респект.
Александр Туниеков
14 ноября 2024, 05:22
0
astro.build впервые слышу такой фреймворк. Вообще gtsAPI затачивался под primevue.org. Но в primevue вообще не никакой связи с api. Там api как хочешь так и делай. Если в astro.build есть какие-то специализированные функции для отправки запросов в бекенд, то gtsAPI, скорее всего, вам не подойдет. А если для бекенда предпологается полный произвол, то связь с gtsAPI можно запрограмировать.
Вы, наверно, знаете astro.build лучше меня и сами можете определить подойдет ли он.
Например
Чтение таблицы
GET /api/tSkladNaryadSmena
или
POST /api/tSkladNaryadSmena?api_action=read
доп параметры:
filters, limit, offset, setTotal, sortField, multiSortMeta
Ответ
{
  "success": 1,
  "message": "",
  "data": {
    "rows": [
      {
        "id": "2098",
        "naryad_id": "17",
        "smena_id": "2084",
        "koef_time": "1.000",
        "close": "1",
...
Более подробно описание api API gtsAPI
Более четкая документация еще только в планах. Сейчас в первую очередь описание PVTables на основе primevue.
Надеюсь понятно и исчерпывающе ответил? :-)
Александр Туниеков
14 ноября 2024, 05:04
0
Что-то modx.pro уведомление не прислало. Случайно увидел что комментарии появились.
Только что попробовал авторизоваться и у меня работает. Может скриншоты ошибок скинете?
Александр Туниеков
04 ноября 2024, 04:49
+1
Еще сейчас заметил у Артура редактируется выбранная группа пользователей. Чтоб редактировать группу 2 в gettables надо добавить в секцию pdoTools where:
'where'=>[
    'modUser.primary_group' => 2,
    'modUser.active' => 1,
]
Александр Туниеков
04 ноября 2024, 04:36
0
Забыл. getTables работает в MODX2. В MODX3 тоже вроде пока работает, но там не гарантируется и приспосабливать getTables для MODX3 не планируется. Работу с произвольной таблицей в MODX3 вроде сильно усложнили и не понятно как сделать правильно.
Александр Туниеков
04 ноября 2024, 03:47
+1
Кстати GRUD в getTables реализован и можно его использовать для подобной задачи :-). У пользователей MODX 2 таблицы и не так просто. Но можно попробовать.

На странице на которую ограничен доступ пишем сниппет:
{'!getTable' | snippet : [
    'table'=>[
        'event'=>1,
        'class'=>'modUser',
        'actions'=>[
            'create'=>[],
            'update'=>[],
            'remove'=>[],
            'export_excel'=>[],
        ],
        'pdoTools'=>[
            'class'=>'modUser',
            'leftJoin'=>[
                'modUserProfile'=>[
                    'class'=>'modUserProfile',
                    'on'=>'modUserProfile.internalKey = modUser.id'
                ]
            ],
            'select'=>[
                'modUser'=>'modUser.id',
                'modUserProfile'=>'modUserProfile.fullname,modUserProfile.email,modUserProfile.phone',
            ],
            'sortby'=>[
                'modUser.id'=>'DESC'
            ]
        ],
        'row'=>[
            'id'=>['filter'=>1],
            'password'=>[
                'edit'=>['type'=>'hidden'],
                'default'=>'Не секретный пароль'
            ],
            'fullname'=>[
                'class'=>'modUserProfile',
                'label'=>'ФИО',
                'edit'=>['type'=>'text','search_fields'=>['internalKey'=>'id'],],
                'filter'=>1,
            ],
            'email'=>[
                'class'=>'modUserProfile',
                'label'=>'email',
                'edit'=>['type'=>'text','search_fields'=>['internalKey'=>'id'],],
                'filter'=>1,
            ],
            'phone'=>[
                'class'=>'modUserProfile',
                'label'=>'Телефон',
                'edit'=>['type'=>'text','search_fields'=>['internalKey'=>'id'],],
                'filter'=>1,
            ],
        ]
    ]
]}
Пишем плагин на событие getTablesAfterUpdateCreate. Для работы плагина в сниппете должно быть указано 'event'=>1, как выше.
<?php
switch ($modx->event->name) {
    case 'getTablesAfterUpdateCreate':
        // $modx->log(1,'getTablesAfterUpdateCreate '.print_r($data,1));
        if($data['table_name'] == 'modUser' and $data['gts_action'] == 'getTable/create'){
            if($modUser = $modx->getObject('modUser',(int)$data['id'])){
                $modUser->set('username',$data['email']);
                $modUser->set('password',md5(date('d.m.Y H:i:s')));
                $modUser->joinGroup(2);
                $modUser->save();
            }
        }
    break;
}
И все работает :-).


Так же можно это же сделать с PVTables, но этот компонент я еще не добрался опубликовать :-(. И писать в 2 таблицы сразу там не сделанно. И события не все прописал :-(.

Безопасность обеспечивается хеш-кодом. Страница на которой опубликован сниппет должна быть доступна только нужным пользователям. Использовать getTables, для подобных задач, думаю, проше и быстрее чем писать контроллеры для sendIt.
Александр Туниеков
04 ноября 2024, 02:38
0
Какая версия MySQL? На MySQL 8 возникала проблема. Он почему-то не воспринимает двойную сортировку.
sort by pagetitle ASC, createon DESC
И MySQL 8 возвращает ошибку. В коде от Ильи двойная сортировка используется и нужна. Когда с этой ошибкой столкнулся не было времени ее решать, но на всякий случай сейчас MySQL 8 не ставлю.
Александр Туниеков
04 ноября 2024, 02:25
0
Тоже интересно что с безопасностью. В коде на гитхабе никаких проверок на доступ. Возможно безопасность обеспечивает SendIt, но автор вообще не указал как SendIt подключается и используется. Наверно в SendIt подключаются прессеты??? В общем, для человека не знакомого с SendIt, как мне, статья вообще не понятная.

Безопасность может быть реализованна таким образом. Сниппет, типа AjaxForm, при обработки страницы, записывает в сессию хеш-код. js в браузере отправляет с формой этот хеш-код. Обработчик ajax запросов на сервере смотрит есть ли в сесии этот хеш-код и если его нет, то возращяет ошибку.
Таким образом, если сниппет не был вызван при обработке страницы, то все ajax запросы завершаться ошибкой. Будут приняты только те запросы с правильным хеш-кодом.
А на ресурс MODX можно поставить ограничения и показывать его только разрешенным пользователям. Соответственно на странице на запрещенном ресурсе сниппет не отработал, хеш-код в сессию не записался и ajax запросы не срабатывают.

В общем не знаю, как безопасность реализованна в SendIt, но наверно что-то подобное. Надеюсь @Артур Шевченко просветит нас :-)
Александр Туниеков
22 августа 2024, 15:18
0
Привет. Посмотри включен ли у тебя режим дебаг в настройках.
Ага нашел.

В этом скрине включен режим отладки. Выключи его
Александр Туниеков
26 июля 2024, 19:44
0
можно наверно и другие типы полей прописать без getTVValue, но я tv почти не использую. Вдаваться в подробности их обработки не буду.
Александр Туниеков
26 июля 2024, 19:29
0
В pdoTools вот код модификатора
$this->_modifiers['resource'] = function ($id, $field = null) use ($pdo, $modx, $fenom) {
            $pdo->debugParserModifier($id, 'resource');
            /** @var modResource $resource */
            if (empty($id)) {
                $resource = $modx->resource;
            } elseif (!is_numeric($id)) {
                $field = $id;
                $resource = $modx->resource;
            } elseif (!$resource = $pdo->getStore($id, 'resource')) {
                $resource = $modx->getObject('modResource', ['id' => intval($id)]);
                $pdo->setStore($id, $resource, 'resource');
            }

            $output = '';
            if (!empty($resource)) {
                if (!empty($field)) {
                    if (strtolower($field) == 'content') {
                        $output = $resource->getContent();
                    } else {
                        $output = $resource->get($field);
                        if (is_null($output)) {
                            $output = $resource->getTVValue(preg_replace('#^tv\.#i', '', $field));
                        }
                    }
                } else {
                    $output = $resource->toArray();
                }
            }
            $pdo->debugParserModifier($id, 'resource');

            return $output;
        };
Судя по $pdo->getStore ресурс где-то кешируется. Но как-то пробовал ускорить сайт 10 вызовов {resource_id | resource: 'tv_param_name'} сильно замедляют сайт.
Я ведь правильно понимаю — использование выше сниппета выше более рационально если надо дергать 5 — 6 полей другого ресурса?
Более рационально, если тип поля text. $resource->getTVValue($tv['name']); делает запросы в базу.
Александр Туниеков
24 июля 2024, 21:56
0
Поправил немного
<?php
$id = $input;
if (empty($id)) {
    $resource = $modx->resource;
} else {
    $resource = $modx->getObject('modResource', ['id' => intval($id)]);
}
if(!$resource) return [];

$out = $resource->toArray();
// чтоб страница не упала в рекурсию
unset($out['content']);

$id = $resource->id;
$sql = "
    SELECT IF(tvr.value != \"\", tvr.value, tv.default_text) AS tv_value, tv.name, tv.type
    FROM {$modx->getTableName('modTemplateVarResource')} tvr
    LEFT JOIN {$modx->getTableName('modTemplateVar')} tv
    ON tv.id = tvr.tmplvarid
    LEFT JOIN {$modx->getTableName('modTemplateVarTemplate')} tvt
    ON tvt.tmplvarid = tvr.tmplvarid 
    WHERE tvr.contentid = {$id} AND tvt.templateid = {$resource->template}
";
// $modx->log(1,$sql);
$q = $modx->prepare($sql);
$q->execute();
$tvs = $q->fetchAll(PDO::FETCH_ASSOC);

foreach($tvs as $tv){
    switch($tv['type']){
        case 'text': case 'textarea':
            $out[$tv['name']] = $tv['tv_value'];
        break;
        default:
            $out[$tv['name']] = $resource->getTVValue($tv['name']);
    }
}
return $out;
Александр Туниеков
24 июля 2024, 21:35
+2
Я тут решил немного помочь и сделал сниппет
res
<?php
$id = $input;
if (empty($id)) {
    $resource = $modx->resource;
} else {
    $resource = $modx->getObject('modResource', ['id' => intval($id)]);
}
if(!$resource) return [];

$out = $resource->toArray();
$id = $resource->id;
$sql = "
    SELECT IF(tvr.value != \"\", tvr.value, tv.default_text) AS tv_value,tv.name
    FROM {$modx->getTableName('modTemplateVarResource')} tvr
    LEFT JOIN {$modx->getTableName('modTemplateVar')} tv
    ON tv.id = tvr.tmplvarid
    LEFT JOIN {$modx->getTableName('modTemplateVarTemplate')} tvt
    ON tvt.tmplvarid = tvr.tmplvarid 
    WHERE tvr.contentid = {$id} AND tvt.templateid = {$resource->template}
";
// $modx->log(1,$sql);
$q = $modx->prepare($sql);
$q->execute();
$tvs = $q->fetchAll(PDO::FETCH_ASSOC);

foreach($tvs as $tv){
    $out[$tv['name']] = $tv['tv_value'];
}
return $out;
Использовать
{set $res = 1 | res}
<pre>{$res | print_r}</pre>
Расчитанно, что все tv текстовые. Если надо чтоб tv обрабатывались перед помещением в массив, то надо вызывать getTVValue.
foreach($tvs as $tv){
    $out[$tv['name']] = $resource->getTVValue($tv['name']);
}
Александр Туниеков
21 марта 2024, 19:47
+1
Клиент сегодня озадачил. Пришлось побороть проблему.
Создаем веб приложение и прописываем в google консоле uri
ваш_сайт/manager/?a=home&namespace=googlesheets
Александр Туниеков
20 марта 2024, 19:11
0
Блин. Насчет того, что точно не буду использовать vesp/core 4 кажется погорячился. Проблема в том, что ресурсов на собственный аналог не хватает :-(. Чтоб предложить более менее полноценное приложение надо потратить много времени… В принципе можно было бы перейти на vesp, но главная проблема отсутствие модульности. У нас сайт с, условно, сотней модулей. Пересоберать весь сайт при изменении одного модуля или добавлении нового желания нет.
У меня, при использовании gtsAPI, на странице вызывается сниппет, который подгружает однофайловый модуль на vue. Который весит пару килобайт. Соберается за секунды и никак не влияет на другие модули. Нужно, чтоб модуль можно было отдельно редактировать и соберать. Чтоб модуль отдельно подгружался при использовании на странице и чтоб при загрузке какой-либо страницы не загружались все сто модулей.
Пример модуля ExcelCalc