Статьи об IT

Записки и шпаргалки по php / modx / extjs и самозабывчивость

Записки и шпаргалки по php / modx / extjs и самозабывчивость

И вначале реклама, небольшой блок. Прошу не сердиться и не вносить ее в фильтры блокировщиков.

подробнее о рекламодателе можно узнать внутри блока
Спасибо. А теперь сам материал.

Заметка-шпаргалка, а практически все пишут себе шпаргалки на своих страничках, по частым моим ошибкам и по провалам в памяти железнобетонных основ и популярных строк в программировании. Сам себя ругаю, что эту элементарщину пишу, но пускай будет. 

Сорри, если это не правильно и не соответствует вашим постулатам. 

1. Уменьшить количество конструкций if else и не использовать для простейших условий, заменять на тернарный оператор. 
Тернарный оператор, синтаксис. Условие ? значение 1, если оно истинно : значение 2, если оно ложно; 
Пример:
if (!empty($test)) { 
$s = $test; 
} else {
$s = ' none'; }

легко заменяется на одну строчку 

$s = (!empty($test)) ? $test : 'none';

2. формат крона: минута час день-месяца месяц день-недели.Например, запуск скрипта каждые два часа по выходным. * */2 * * 6,7

Кстати, через cron можно передавать параметры, забираются они $argv[1], $argv[2] и т.д. ....

3. НЕ ИСПОЛЬЗОВАТЬ НИКОГДА $_REQUEST! а $_GET делать максимально безопасным

Например я знаю, что данные передаваемые в GET будут числом. А значит нам ничего кроме числа не нужно. 

Кстати, в modx есть замечательные методы для очистки значений.
$modx->sanitize($data, $modx->sanitizePatterns); - для очистки массива, 
$modx->stripTags($var); - для очистки строки.
Данным способом modx не только почистит от нежелательных тегов, но и от специфических для платформы. strip_tags также можно использовать в чанках.

Итак, мы ожидаем число из GET:

$cid = htmlentities(strip_tags($_GET['q']));
if (!is_numeric($cid)) { echo 'не число'; die; }
$cid_f=intval($cid);

паранойа? да.

4. НИКОГДА НЕ ДЕЛАТЬ НЕ ПОДГОТОВЛЕННЫЕ ЗАПРОСЫ В БАЗУ. Особенно, если запрос зависит от GET, POST и других переменных. 

Что я имею ввиду, давно давно, буквально недавно, я даже получая данные с API делал по традиции $conn->query("SELECT * FROM t1 WHERE `id`=".$id.""); ну или как-то так. Никогда не нужно никакие запросы делать к базе с переменными, а уж тем более, если это операции по UPDATE, DELETE, INSERT. Разве что truncate, да и то не всегда. И особенно, если эти данные передает сторонний сервер\человек. 

Всегда необходимо делать через Подготавливаемые запросы или statement.  С помощью Prepare() проверяется правильность и безопасность запроса, а потом execute - его выполнение, при этом в запрос необходимо вставлять специальный плейсхолдер символом "?". Заодно можно и проверять на тип значения. Плейсхолдеров может быть много в bind_param прописываются без разделения (iii, sii и др).

$stmt = $mysqli->stmt_init();
$sql = "SELECT * FROM t1 WHERE id > ? ";
$stmt->prepare($sql);
$stmt->bind_param("i", $id);
$stmt->execute();

Более подробно тут: https://php.ru/manual/mysqli-stmt.prepare.html

не забыть обработать ошибки при этом. Например в MODX  я пишу сразу в лог

if (!$q = $modx->prepare($sql)) {
$modx->log(MODX_LOG_LEVEL_ERROR, 'Ошибка выполнения запроса ' . $sql . ' : ' . $q->errorInfo()[0] . '->' . $q->errorInfo()[1] . '->' . $q->errorInfo()[2]);
die;}

if (!$q->execute()) {
$modx->log(MODX_LOG_LEVEL_ERROR, 'Ошибка выполнения запроса ' . $sql . ' : ' . $q->errorInfo()[0] . '->' . $q->errorInfo()[1] . '->' . $q->errorInfo()[2]);
die;}

и потом уже $result = $q->fetchAll(PDO::FETCH_ASSOC);

Также в MODx можно проверить запрос $q->toSQL(); для себя, если что-то идет не так.

5. В MODx есть чудесный клиент для CURL.

Часто необходимо работать с php curl, так вот для простых запросов в modx есть полезный инструмент

$client = $modx->getService('rest', 'rest.modRest');
$client->setOption('timeout', 15);
$client->setOption('header', true);
$client->setOption('connectTimeout',15);
$params = array ('параметры' => $var,);
$url = 'адрес';
$response = $client->get($url, $params);

Проверяем, что сервер вернул ответ 200 и в целом соединился. 
if (property_exists($response->responseInfo, 'scalar') and $response->responseInfo->scalar != '200') {
$modx->log(MODX_LOG_LEVEL_ERROR, 'Ошибка запроса: '.$response->responseInfo->scalar.' '.$response->responseError.'. Header: '.print_r($response->responseHeaders, true));
die;
}

Получает нужную нам информацию в JSON.
$data = $response->process();

Более подробно тут: https://modx.pro/howto/18715

 6. В ExtJS modx не работает paging. 

Это сложно для понимания и прочтения. При написании своей странички в панели управления modx я заметил, что не работает листание страниц, несмотря на paging, true. Если поменять количество выводимых строк, то панель выведет это количество, однако же напишет, что их столько и есть и листание делать нельзя. 20 - показано 20 или 20. 50 - показано 50 из 50. Если делать поиск, то работает. Но вот листание нет. Будто на одной странице уже все показано. Путем долгих мучений обнаружено, что все это из-за отсутствия primary id в описании модели таблицы, а точнее в описании класса таблицы и map.inc.php. Если я добавляю в таблицу любимое многими id с auto auto increment, а класс для таблицы наследую соответственно xPDOSimpleObject - то все работает. Но, у меня уникальное поле другое, например c_id, и оно не должно быть автоинкрементированно, а берется с API. В таком случае xPDOSimpleObject не выведет в Grid вообще ничего, а в лог упадет ошибка [2] => Unknown column 'КлассТаблицы.id' in 'field list'. Путем долгой ночи и кофе (страшных мучениях муков выбора добавить id или решать вопрос) я вернулся обратно к xPDOObject и нашел на просторах такой код, который нужно добавить в .map.inc.php

'extends' => 'xPDOObject',
'fields' => 
array(
'c_id' => '',
),
'indexes' =>
array (
'c_id' =>
array (
'alias' => 'c_id',
'primary' => true,
'unique' => true,
'type' => 'BTREE',
'columns' =>
array (
'competition_id' =>
array (
'length' => '12',
'collation' => 'A',
'null' => false,
),
),
),
), 

'fieldMeta' =>
array( 
'c_id' =>
array(
'dbtype' => 'int', 
'precision' => '12', 
'phptype' => 'string', 
'null' =>false, 
'default' => '', 
'attributes' => 'unsigned',
'index' => 'index',
),

Не ручаюсь насколько это правильно и истинно, но именно в таком случае заработало листание страниц, без добавления не нужного для меня еще одного поля в таблицу БД id и уж темболее с автозаполнением. Честно говоря я очень долго думал в споре xPDOObject или xPDOSimpleObject, но к сожалению как ни крути, не всегда таблицы должны содержать id и потому придется познавать тонкости классов xPDO. 

7. ExtJs Modx выбрать в combo значение и получить его при нажатии на кнопку. 

Еще с предыдущего пункта стоило уточнить, что я не профи и не спец и все познается путем гугления, стоковерфловывания, docsenchaения, модикспрочтения. Такая задача, выбрать в выпадающем списке поле, значение поля потом должно при нажатии на кнопку уйти на php. 
{
xtype: 'combo',
name: 'name_combo',
hiddenName: 'name_combo',
id:'id_combo',
mode: 'local',
allowBlank : false,
emptyText: '== Текст, когда ничего не выбрано ==',
store: new Ext.data.ArrayStore({
id: 0,
fields: ['id','text'],
data: [
['1','Текст выборки'],
['2','Текст выборки'],
['3','Текст выборки'],
['4','Текст выборки'],
],
}),
displayField: 'text',
valueField: 'id',
},
{
xtype: 'button',
id: 'id_button',
text: ' Текст кнопки',
handler: function () {
let pr = Ext.getCmp('id_combo').getValue();
if(pr == '') {
MODx.msg.alert('Внимание!','Ничего не выбрано');
} else {

Ext.Ajax.request({
url: '/path/to/file.php?z='+pr,
type: 'json',
async : false,
method: 'POST',
success: function (response, options) {
//что-то делаем, когда успешно

},
failure: function (response, options) {
//что-то делаем, когда все грустно
}
});
this.refresh();
}
}
}

Я не смог побороть, чтобы обновление grid было в случае успешного выполнения. Что не делал и как не обращался. Рефреш работает только после всего выполнения request.

8. Рендеринг полей в ExtJS. 

Когда я разгребал один проект для меня было шоком, что поля выводились как есть в Grid, типа 0\1 или непропорциональная картинка. 

Для рендера есть наиболее мной часто используемые

{dataIndex: 'img', width: 100, header: 'Иллюстрация', renderer: function (value) {
if(value){
return 'тут тег картинки, где в конце +value+ точка jpg style = height:80px'; // указывает только высоту, чтобы все картинки органично смотрелись, но не сжимались. Однако можно применять и aspect-ratio.
}else {return ''}
}}

Для рендера "да\нет"

{dataIndex: 'active',sortable: true, width: 70, header: 'Активен', renderer: function (value) {
if (value == 1) {
return 'Да';
} else {
return 'Нет';
}
}
}

А вообще рекомендую к прочтению весь цикл этих статей: https://ilyaut.ru/extjs/how-modx-extras-work-1/

9. Контекстные меню в ExtJS grid. 

Очень удобно делать быстрые действия в сетке extjs путем нажатия на правую клавишу мыши. например сделать неактивным или снять с главной страницы. 

Это все делает getmenu

getMenu: function(grid,idx) {
var row = grid.store.data.items[idx];
var m = [
{
text: ' Редактировать',
handler: this.updateItem
},

];
if (row.data.active == 0) {
m.push({
text: ' Сделать активным',
handler: this.EnableTest
}
);
}
else {
m.push({
text: ' Сделать неактивным',
handler: this.DisableTest
});
}
if (row.data.view_index == 1) {
m.push({
text: ' Скрыть с главной страницы',
handler: this.DisableViewIndex
})
} else {
m.push({
text: ' Показать на главной странице',
handler: this.EnableViewIndex
})
}
m.push('-', {
text: ' Удалить',
handler: this.removeTests
})

this.addContextMenuItem(m);
return true;
},

А вот за двойной клик мыши по сетке

rowDblClick: function(grid, rowIndex, e) {
var row = grid.store.getAt(rowIndex);
this.updateItem(grid, e, row);
}

10. И еще чуть-чуть про ExtJS 

Для меня удобно все xtype разносить в разные файлы, для дальнейшей правки. Самое мучительное было раскладывать API ответ через extjs с кучей скобок и запятых, поэтому не нужно забывать про табуляцию. Для ExtJS подойдет монитор, в котором можно поменять ориентацию дисплея (вращающийся дисплей на 900). Делать нормальные названия Gridov и списков. 

11. И еще про MODx

А точнее про разработку компонентов и сниппетов. Для себя отметил удобство многих данных заносить в системные настройки, а потом обращаться через $modx->getOption(ключ, опция, значение по умолчанию, пропуск пустого значения).

Уровнь записи в логи modx

MODX_LOG_LEVEL_FATAL / modX::LOG_LEVEL_FATAL = 0 - фатальная ошибка
MODX_LOG_LEVEL_ERROR / modX::LOG_LEVEL_ERROR = 1 - ошибка
MODX_LOG_LEVEL_WARN / modX::LOG_LEVEL_WARN = 2 - предупреждение
MODX_LOG_LEVEL_INFO / modX::LOG_LEVEL_INFO = 3 - информационные сообщения
MODX_LOG_LEVEL_DEBUG / modX::LOG_LEVEL_DEBUG = 4 - отладочные сообщения

12. И еще 

Попробовал как-то Яндекс speeachKit и перевод налету с ExtJS. Мне понравилось :-) Смысл такой, берем поле с текстом и по ajax.request отправляем на свою сервисную php страничку, которая уже соединяется с облачными вычислениями яндекса и возвращает json текста или аудио. Полученный результат мы: 1. если это перевод - заполняем в setValue полей extJs, 2. если аудио - пишем путь в поле . Сохраняем. Радуемся. У меня это делается буквально за секунду.  
Полный путь: ExtJS получил данные с API заполнив тектовые поля в форме, далее нажимаю перевести - текст считался и заменился уже переводом, далее озвучить - получил озвучку текста. После чего нажал сохранить на форме и все это улетело в Базу. Главное, не забывать отдельно или в консоль выводить оригинал текста, иногда Яндекс уж очень дословно переводит фамилии или имена. Эти технологии платные, но при небольших обьемах стоит все недорого. 

 И скопом php

$_SERVER:
['DOCUMENT_ROOT'] - корневой каталог,
['HTTP_ACCEPT_LANGUAGE'] - язык,
['HTTP_HOST'] - имя сервера домена,
['HTTP_REFERER'] - откуда,
['HTTP_USER_AGENT'] - браузер,
['REMOTE_ADDR'] - ip,
['QUERY_STRING'] - переданные параметры,
['REQUEST_URI'] - путь урл от корня

in_array - поиск элемента в массиве (элемент, массив), array_key_exists - поиск ключа, array_search - поиск значения (true/false), array_sum($arr) - сумма числовых элементов массива, shuffle - перемешать массив, array_unique - уникальные значения,  сортировка массивов sort (и производные, в зависимости от типа массива). isset - существование самой переменной, empty - а это существование значения переменной (пусто или не пусто). 

Я очень часто простой код проверяю в php консоли modx - это такое дополнение, где можно из админки что-то протестить не на виду у всех. Так вот, чтобы увидеть все ошибки php необходимо перед скриптом указать

ini_set('error_reporting', E_ALL);
ini_set('display_errors', 1);
ini_set('display_startup_errors', 1);

Очень много проверок можно делать в чанке modx, мой самый популярный

[[+name:is=``:then=``:else=`[[%[[+name]]? &namespace=`ПространствоИмен`]]`]]  - здесь я также использую лексикон, в который завожу значения на русском языке. 

Иногда в чанках как зря работало определение типа устройства пользователя, приходится так выводить

[[!MobileDetect:is=`1`:then=`что-то для не мобильных`:else=``?input=`standard`]]

upd. Очистить кэш в modx из компонента

function() {
MODx.clearCache();
},MODx);

Ну или просто MODx.clearCache();, например при нажатии на кнопку, в всплывающем окне, или в success request и т.д.

 ------------------

Прошу прощения, если что-то не так, или кажется слишком простым. 

Похожее

draw I
draw I
draw I
draw I

 quote a81ca

Если вдруг вам было здесь полезно, уютно и приятно, что захотелось меня отблагодарить - вы можете пожертвовать мне на кофе.

 

i

Будет осуществлен переход на сайт Yoomoney

 

draw I

 


Внимание: На сайте могут присутствовать ссылки ePN

Мини-портфолио

очередной бесполезный блог