0.00
97 читателей, 78 топиков

[REVO] Кейс: Профайлы преподавателей, или getResources слишком долгий

Под моим надзором находится сайт онлайн-школы. И есть на этом сайте страничка с профайлами преподавателей. Фактически она представляет собой опубликованный родительский ресурс с неопубликованными ресурсами для каждого из преподавателей. Вся информация о преподавателе расположена в «телевизорах» (TV).
На сайте профайл представляет собой ссылку в виде Фото+Имя и всплывающее окошко с более подробной информацией и формой записи на обучение. Все профайлы подцеплялись при помощи getResources и выводились списком.
К тому же есть пара переключателей, которые генерировали список Ajax-запросом без перезагрузки страницы – это «Язык» и «Носитель языка/Русскоязычный преподаватель».
Собственно, это была предыстория.

Профайлов не так уж много – 20-25, однако скорость генерации списка с помощью getResources заставляла меня плакать навзрыд – 5-12с. И чем больше, я знакомился с его документацией, тем меньше я верил в его нормальную работоспособность.


Читать дальше →

[REVO] Breadcrumbs – Убираем ссылки с неопубликованных ресурсов

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

Читать дальше →

[REVO] Избавляемся от дубликатов alias

Сложилась такая ситуация, что при импорте данных, url генерируется автоматически, и было очень много дубликатов, что не позволяло открывать страницы с дублирующими alias.

Ниже приведено решение, которое производит поиск дубликатов и их редактирование.
При это редактируются не все найденные alias, а только второй и последующий, это делается для того чтобы оставить 1 оригинал.

Редактирование происходит путем добавления id в начало адреса страницы.

<?php
error_reporting(0);
mysql_connect('localhost','','');
mysql_select_db('');

$d = mysql_query("SELECT group_concat(`id`) ids, count(id) c FROM `revo_site_content` GROUP by concat(uri) HAVING c > 1");
while($res = mysql_fetch_array($d))
{
$ids = explode(",",$res['ids']);
$i = 0;
foreach($ids as $id)
{
	$i++;
	if($i == 1)
		continue;
	echo $id . "\r\n
";
	$m = mysql_fetch_array(mysql_query("SELECT uri FROM `revo_site_content` WHERE id = $id"));
	$uri = $m['uri'];
	$uri2 = explode("/",$uri);
	$uri2 = end($uri2);
	$uri = str_replace($uri2,$id."-".$uri2, $uri);
		
	mysql_query("UPDATE `revo_site_content` SET `uri` = '".$uri."', `alias` = CONCAT('".$id."-',`alias`) WHERE `id` = '$id'");
}
}


Настройки

Указываем данные для подключения к БД
mysql_connect('localhost','','');
mysql_select_db('');


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

[REVO] Удаление старых изображений. Скрипт

Данный скрипт позволяет удалять изображения с сервера, которые уже не используются в работе системы.

1) Скрипт работает! только с tv параметрами.
2) Не является плагином или сниппетом

Настройки:

1) Настраиваем подключение к БД
$host = ''; //Database host
$user = ''; //User
$pass = ''; //Password
$dbname = ''; //Database name


2) Указываем имя таблицы со значениями tv параметров
$table_name = 'revo_site_tmplvar_contentvalues'; //Table name


3) Указываем id tv параметра который отвечает за изображения. При этом скрипт обрабатывает как одиночные так и мультизагруженные изображения например через MIGX
$tmplvarid = ''; // Required value for tmplvarid


4) Указываем имя папки с изображениями. Необходимо учесть путь о корня. Также прошу обратить внимание что данная версия скрипта не смотрит сквозь вложенные папки.
$folder_name = ''; //FoНастрlder with images


5) Настраиваем работу скрипта по крону.

Прошу учесть что вся работа скрипта проверялась на vds при 20000 изображений. При этом было удалено порядка 9000 устаревших файлов.

<?php
$host = 'localhost'; //Database host
$user = ''; //User
$pass = ''; //Password
$dbname = ''; //Database name
$table_name = 'revo_site_tmplvar_contentvalues'; //Table name
$tmplvarid = ''; // Required value for tmplvarid
$folder_name = 'images'; //FoНастрlder with images


$connect = mysqli_connect($host, $user, $pass);

//Get files list
$files_list = scandir($folder_name);
unset($files_list[0]);
unset($files_list[1]);
$files_list_accoc = array_flip($files_list);
mysqli_set_charset($connect, "utf8");
echo "<p>Files list:</p>";
$i = 1;
foreach($files_list as $value)
	{
	echo $i . ". " . $value . "
";
//Searching for files in database
	$q = "SELECT * FROM " . $dbname . "." . $table_name . " WHERE tmplvarid=" . $tmplvarid . " AND value like '%" .$value. "%'";
	$result = mysqli_query($connect, $q);
	$rows = mysqli_num_rows($result);
//Remove from list if exist
	if ($rows == 1)
		{
		unset($files_list_accoc[$value]);
		}
	$i++;
	}
mysqli_close($connect);
$files_list_trash = array_flip($files_list_accoc);
echo "<hr><p>Useless files:</p>";
$ii = 1;
//Removing of useless files
foreach($files_list_trash as $value)
	{
	$command = "rm -rf " . $folder_name . "/" . $value;
	echo $ii .". '" .$command. "'
"; 
	//Test it, before uncomment next line
	exec($command);
	$ii ++ ;
	}
?>


removeOldImage git

Данное решение используется для узко-направленных задач и не всем может подойти.

eForm - ограничение максимального количества символов и вывод сообщения об ошибке

По аналогии с проверкой размера файла, сделал проверку количества вводимых символов в textarea с выводом сообщения.
Вызов формы:
[!validatetextsize!]
[!eForm? ... &eFormOnValidate=`validatetextsize`!]

в чанке &tpl:
<textarea name="text" eform="Обращение ::0"></textarea>

сниппет validatetextsize:
<?php
function validatetextsize($fields,&$vMsg,&$rMsg){
       if (strlen(htmlspecialchars($fields['text']))>2500){//имя элемента массива совпадает с аттрибутом name
		$vMsg[]='Превышен максимальный размер сообщения 2500 символов';
	}
        return; 
};
?>

не уверен в необходимости использования тут htmlspecialchars(), но на всякий случай поставил.
правки и дополнения приветствуются

UPDATE
то же самое, но с добавлением класса для подсветки невалидного поля с помощью css
<?php
function validatetextsize($fields,&$vMsg,&$rMsg,&$rClass){
       if (strlen(htmlspecialchars($fields['text']))>2500){//имя элемента массива совпадает с аттрибутом name
		$vMsg[]='Превышен максимальный размер сообщения 2500 символов';
                $rClass['text'] = 'invalid';
	}
        return; 
};
?>


UPDATE 2
для сайтов в UTF-8 кодировке рекомендуется использовать mb_strlen() для подсчета кириллических символов

[EVO] eForm - вывод сообщения о превышении допустимого размера файла

Долго искал, готовых решений не нашел, на основании этого топика сделал простое решение. Вызов формы:
[!validatefilesize!]
[!eForm? ... &eFormOnValidate=`validatefilesize`!]

в чанке &tpl:
<input type="file" name="testfile" eform="Файл :file:0">

сниппет validatefilesize:
<?php
function validatefilesize($fields,&$vMsg,&$rMsg){
	if ($_FILES['testfile']['size'] > 1024){  //имя поля и максимальный размер файла    
		$vMsg[]='Размер файла больше допустимого';
	}
	return; 
};
?>

думаю много кому пригодится, правки и дополнения приветствуются.

[EVO] Установка заголовка Last-Modified и 304 Not Modified для поисковых систем (Update от 15.11.2014)

Зачем нужен Last-Modified

HTTP заголовок Last-Modified сообщает клиенту время последнего изменения страницы (объекта). Если клиент (браузер, поисковый робот) получил заголовок Last-Modified, то при следующем обращении к адресу, при условии, что страница (объект) есть в локальном кеше, он добавит вопрос If-Modified-Since (не изменилась ли страница после даты, полученной в Last-Modified). В свою очередь сервер, получив запрос If-Modified-Since должен сверить полученную временную метку с временем последнего изменения страницы и, если страница не изменялась ответить 304 Not Modified.
Если страница не изменилась, то сервер прекратит передачу данных после отправки заголовков с кодом 304 Not Modified, тело страницы, изображения и другие объекты передаваться не будут.
Для поисковых же систем это полезно тем что за один и тот же промежуток времени робот успеет проиндексировать больше новых страниц на вашем сайте, потому что не будет загружать страницы которые не поменялись.

Читать дальше →

[REVO] Какие параметры сортировки есть у Gallery?

Какие параметры сортировки есть у Gallery? Никак не могу найти какие значения может принимать параметр sort. Конкретно мне необходимо выводить изображения по цифрам по порядку, например: 01-ОП, 02-ОП, 03-ОП…

[EVO] Автозамена названия чанков и TV в шаблонах, чанках, TV и содержимом ресурсов

Ковыряя японскую ветку MODX, нашел такой функционал — при изменении названия чанка или TV, автоматом обновлялись шаблоны, чанки, TV и содержимое ресурсов.
Вот накидал плагин
<?php
/**
 * Chunk&TV-sync
 *
 * Автозамена названия чанков и TV в шаблонах, чанках, TV и содержимом ресурсов
 *
 * @category    plugin
 * @version     0.1
 * @internal    @events         OnBeforeChunkFormSave,OnBeforeTVFormSave
 * @internal    @properties     
 */
 
if (!defined('MODX_BASE_PATH')) { die('HACK???'); }
$prefix=$this->db->config['table_prefix'];
switch ($_POST['a']) {
    case "79": // update chunk
        $was_name = $modx->db->getValue($modx->db->select('name', $prefix.'site_htmlsnippets', "id='{$id}'"));
        $name = stripslashes($_POST['name']);
        $was_name = str_replace("'", "''", $was_name);
        $name = str_replace("'", "''", $name);
        if ($name !== $was_name) {
            $modx->db->update("content=REPLACE(content,'{{{$was_name}}}','{{{$name}}}')", $prefix.'site_content');
            $modx->db->update("content=REPLACE(content,'{{{$was_name}}}','{{{$name}}}')", $prefix.'site_templates');
            $modx->db->update("snippet=REPLACE(snippet,'{{{$was_name}}}','{{{$name}}}')", $prefix.'site_htmlsnippets');
            $modx->db->update("value=REPLACE(value,    '{{{$was_name}}}','{{{$name}}}')", $prefix.'site_tmplvar_contentvalues');
            $modx->db->update("content=REPLACE(content,'{{{$was_name}:','{{{$name}:')", $prefix.'site_content');
            $modx->db->update("content=REPLACE(content,'{{{$was_name}:','{{{$name}:')", $prefix.'site_templates');
            $modx->db->update("snippet=REPLACE(snippet,'{{{$was_name}:','{{{$name}:')", $prefix.'site_htmlsnippets');
            $modx->db->update("value=REPLACE(value,    '{{{$was_name}:','{{{$name}:')", $prefix.'site_tmplvar_contentvalues');
        }
        break;
    case "302": // update TV
        $was_name = $modx->db->getValue($modx->db->select('name', $prefix.'site_tmplvars', "id='{$id}'"));
        $name = stripslashes($_POST['name']);
        $was_name = str_replace("'", "''", $was_name);
        $name = str_replace("'", "''", $name);
        if ($name !== $was_name) {
            $modx->db->update("content=REPLACE(content,'[*{$was_name}*]','[*{$name}*]')", $prefix.'site_content');
            $modx->db->update("content=REPLACE(content,'[*{$was_name}*]','[*{$name}*]')", $prefix.'site_templates');
            $modx->db->update("snippet=REPLACE(snippet,'[*{$was_name}*]','[*{$name}*]')", $prefix.'site_htmlsnippets');
            $modx->db->update("value=REPLACE(value,    '[*{$was_name}*]','[*{$name}*]')", $prefix.'site_tmplvar_contentvalues');
            $modx->db->update("content=REPLACE(content,'[*{$was_name}:','[*{$name}:')", $prefix.'site_content');
            $modx->db->update("content=REPLACE(content,'[*{$was_name}:','[*{$name}:')", $prefix.'site_templates');
            $modx->db->update("snippet=REPLACE(snippet,'[*{$was_name}:','[*{$name}:')", $prefix.'site_htmlsnippets');
            $modx->db->update("value=REPLACE(value,    '[*{$was_name}:','[*{$name}:')", $prefix.'site_tmplvar_contentvalues');
        }
        break;
}

UPD
поправил

Выборка по алфавиту с фильтрацией по букве

Хотелось, чтобы формировался список по первой букве, и список этих букв, а потом при нажатии на букву отфильтровывалось.
Все в общем на базе сниппета snippet.DLFirstChar (Группировка документов по первой букве) от Agel_Nash Спасибо ему за правку сниппета огромное!

Формируется два списка буквы(для сортировки) и сам список блоков по первой букве названия ресурса.
В принципе по запросу «фильтрация блоков с помощью jquery» в Яндексе много по этому есть.
Надо скачать отсюда тут много разных эффектов или сразу отсюда (здесь можно выбросить картинки и оставить только папки scripts и stylesheets) — копируем например в папку jqsort

На странице, где все это делаем такие вызовы:

<link href="jqsort/stylesheets/screen.css" type="text/css" rel="stylesheet" media="screen,projection" />
<script type="text/javascript" src="jqsort/scripts/jquery.js"></script>
<script type="text/javascript" src="jqsort/scripts/framework.js"></script>

<ul id="filter">
<li class="current"><a href="#">All</a></li>
[!DLFirstChar? &parents=`xxx` &idType=`parents` &orderBy=`BINARY pagetitle ASC` &tpl=`FCharTpl1` &tplOnNewChar=`FCharTplOnNew1`!]
</ul>

<ul id="portfolio">
[!DLFirstChar? &parents=`xxx` &idType=`parents` &orderBy=`BINARY pagetitle ASC` &tpl=`FCharTpl` &tplOnNewChar=`FCharTplOnNew` !]
</ul>

xxx- id папки, откуда берете документы для сортировки
Чанки:
FCharTpl
[+CharSeparator+][+OnNewChar+]<a href="[+url+]">[+pagetitle+]</a>

FCharTplOnNew
<li class="[[FCharToLower? &str=`[+char+]`]]"><h4>[+char+] <small>([+total+])</small></h4>

&tplCharSeparator=`FCharTplSeparator` этот чанк не использовал, но если кому надо, то можно включить
FCharTpl1
[+CharSeparator+][+OnNewChar+]

FCharTplOnNew1
<li><a href="#">[+char+]</a></li>

+++++++++++
Сниппет FCharToLower(делает букву строчной)

<?php
$output = $str;
$str = mb_strtolower($str);
echo $str;
?>