Дмитрий

Дмитрий

Был в сети 16 декабря 2018, 15:34
Заказы не принимаю
Например, я делаю аякс запрос на ресурс со сниппетом. Ресурс должен быть без шаблона, иначе вместе с данными загрузится шаблон. (эдакая матрешка, шаблон в шаблоне). Допустим, содержимое ресурса следующее:
[[!pdoPage?
    &element=`ads_all_pages_pdo`
    &context=`[[*context_key]]`
    &action=sell
    &item_type=all
    &status_filter=online
    &limit=`10`
]]
<div class="pagination">
[[!+page.nav]]
</div>
Значит при выводе данных, странички будут с линком на ресурс который был вызван.
т.е. при переходе на другую страницу, я автоматом получу страницу с данными но без шаблона. :D
Огромное спасибо! Вот так вроде бы работает:
Линк:
warframe.trade/testpages.html
$limit = $scriptProperties['limit'];
if ($page==1) $scriptProperties['offset'] = 0; // иначе не показывает первую страницу
$OFFSET = 'LIMIT '.$scriptProperties['offset'].','.$limit;
...
if ($result_count->num_rows > 0) {
	while($row = $result_count->fetch_assoc()) {
		$sumrows[] = $row;
	}
}
$sum_rows = $sumrows[0]['count'];
...
$number = $scriptProperties['offset']+1;
...
$modx->setPlaceholder('page.total', $sum_rows);
return $SearchResultTableWrapper;
Наверное откажусь от аякса, это не рентабельно + геморно. По крайней мере сделать Get на этой же странице, кажется гораздо проще.

Без pdoPage выводит собранный чанк целиком.
Перед тем, как задействовать pdoPage меняю:
$SearchResultTableItems = '';
...
$SearchResultTableItems .= $modx->getChunk('ads_items', Array(
на
$SearchResultTableItems = Array();
...
$SearchResultTableItems[] = $modx->getChunk('ads_items', Array(
и вывожу не
return $SearchResultTableWrapper
а
return $SearchResultTableItems;
Иначе ведь, pdoPage не поймет как нужно разделить цельный html код на страницы?
К сожалению, все делает один человек.
Что реализовано:
1. Пользователь выбирает из mysql таблицы предмет любого типа, и выставляет его на покупку либо продажу.
2. Данные с id пользователя, id-предмета, его характеристиками (они могут быть разные, скажем уровень раскачки предмета) и ценой идут в таблицу buy либо sell.
3. Допустим 100 пользователей закинуло в эти базы свои заявки, по 20-30 заявок каждый. Итого 2000-3000 заявок.

Что обернуть в pdoTools:
4. Показ сразу всех заявок на странице «Все заявки». На данный момент, я ограничил запрос к выборке buy и sell до 30, иначе, загружается слишком много данных на одну страницу. Настолько, что страница махом отжирает 200мб оперативки, и пользоваться сайтом становится проблематично.
Поэтому нужна многостраничность, т.е. нужен постраничный вывод строк таблицы.

PS:
Почти закончил решение без pdoTools, аля костыль, но понимаю что это не дело. Опробовав однажды запрос по модели, почувствовал такооое облегчение.
Я так много на быдлокодил, что уже путаюсь при попытке встраивания чего-то стороннего. Пожалуй, откажусь от идеи использовать pdoPage. Потом, когда-нибудь, когда это не будет столь критично по срокам для самого себя.

Когда писал этот топик совсем отчаялся сделать красиво с pdo. И поэтому решил забить на него, и практически разобрался со своим же кодом. Пагинация работает. Осталось продумать алгоритм для вывода страниц like pdoPage.

Простите, за потраченное время. То, что «почти получилось», на деле отказалось работать, видимо я снова что-то упустил. Уже нет сил плавать в чем-то непонятном. И схватиться не за что. Читал про pdoTools на
docs.modx.pro/, но так ине понял как это работает. Видимо читатель должен знать какие-то основы, которые я даже не знаю как гуглить. Надо взять в привычку изучать ВСЮ документацию, вероятно тогда и проблем не будет. ;)

Но если интересно, то вот мой быдлокод, приятного чтива xD):
Ссылка на страницу
Ресурс «Все объявления»:
[[!result_tables_new_all?
  &context=`[[*context_key]]`
  &action=buy
  &item_type=all
  &status_filter=online
]]
Сниппет «result_tables_new_all», который используется на разных страницах, с немного разными данными:
<?php
error_reporting(E_ALL | E_STRICT);
ini_set('display_errors', 1);

//id пользователя который запускает сниппет
$user = $modx->getUser();
$real_id = $user->get('id');

if(!empty($_SERVER['HTTP_X_REQUESTED_WITH'])) {
	$context = $modx->context->key;
	$action = $_POST['action'];
	$item_type = $_POST['item_type'];
	$filter_mod_count = $_POST['filter_mod_count'];
	$status_filter = $_POST['status'];
	$ajax = 1;
	if($_POST['from_profile'] == 1){
		$user_name = $_POST['user_name'];
		$user_id = $_POST['user_id'];
		$user_edit = 1;
		$from_profile = $_POST['from_profile'];
	}
}
//Добавим Unixtime для треба онлайна
$mysqli = $modx->runSnippet('mysql');
	switch($action){
		case 'buy':
			$TABLE = '`darvo_a_buy`';
			break;
			
		case 'sell':
			$TABLE = '`darvo_a_sell`';
			break;
	}
	//Проверка статуса Онлайн
	$status = Array();
	switch($status_filter){
		case 'offline':
			$WHERE = '';
			$status['color'] = 'red';
			$status['status'] = 'Offline';
			break;
		case 'online':
			$WHERE = 'WHERE `unixtime`>= unix_timestamp() - 60';
			$status['color'] = 'greenyellow';
			$status['status'] = 'Online';
			break;
	}
	
	$JOIN_UNIXTIME = 'LEFT JOIN `darvo_online_users` ON  '.$TABLE.'.`user_id` = `darvo_online_users`.`id`';
	$JOIN_USERNAME = 'LEFT JOIN `modx_user_attributes` ON '.$TABLE.'.`user_id` = `modx_user_attributes`.`id`';
	$JOIN = $JOIN_UNIXTIME.' '.$JOIN_USERNAME;
	$SELECT = $TABLE.".`id`,".$TABLE.".`user_id`,".$TABLE.".`item_type`,".$TABLE.".`item_id`,".$TABLE.".`item_count`,".$TABLE.".`item_price`,`darvo_online_users`.`unixtime`,`modx_user_attributes`.`fullname`";
	
	$page = $_GET['page'];
	if (!preg_match('/^[0-9]+$/', $page)){
	   $page = 1;
	}
	
	$limit = 10;
	if($page>1){
		$current_page = $page*$limit;
	}else{
		$current_page = 1;
	}
	$OFFSET = 'LIMIT '.$current_page.','.$limit;

	//если запрос идет из пользовательского профиля
	if($from_profile == 1){
		if($item_type=='all'){
			$result = $mysqli->query("SELECT * FROM ".$TABLE." ".$JOIN." ".$WHERE." AND `user_id` = ".$user_id." ORDER BY `id` DESC");
		}else{
			$result = $mysqli->query("SELECT * FROM ".$TABLE." ".$JOIN." ".$WHERE." AND `user_id` = ".$user_id." AND `item_type`='".$item_type."' ORDER BY `id` DESC");
		}
	}else{
		if($item_type=='all'){
			$result = $mysqli->query("SELECT ".$SELECT." FROM ".$TABLE." ".$JOIN." ".$WHERE." ORDER BY `id` DESC ".$OFFSET);
			$result_count = $mysqli->query("SELECT COUNT(*) AS 'count' FROM ".$TABLE." ".$JOIN." ".$WHERE);
		}else{
			$result = $mysqli->query("SELECT ".$SELECT." FROM ".$TABLE." ".$JOIN." ".$WHERE." AND `item_type`='".$item_type."' ORDER BY `id` DESC ".$OFFSET);
			$result_count = $mysqli->query("SELECT COUNT(*) AS 'count' FROM ".$TABLE." ".$JOIN." ".$WHERE." AND `item_type`='".$item_type."'");
		}
	}
	
//Общее количество строк
	if ($result_count->num_rows > 0) {
		while($row = $result_count->fetch_assoc()) {
			$sumrows[] = $row;
		}
	}
	$sum_rows = $sumrows[0]['count'];
	$sum_pages = ceil($sum_rows/$limit);

	$pages = $modx->GetChunk('pages',Array(
		'1'=>intval($page-2),
		'2'=>intval($page-1),
		'3'=>intval($page),
		'4'=>intval($page+1),
		'5'=>intval($page+2),
	));
	//return $pages;
	
	if ($result->num_rows > 0) {
		while($row = $result->fetch_assoc()) {
			$founds[] = $row;
		}
	}
	
//return mysqli_error($mysqli);
$SearchResultTableItems = '';
$number = 1;
foreach($founds as $found){
	if($from_profile != 1){
		$user_name = $found['fullname'];
		$user_id = $found['user_id'];
	}
		
	$result = $mysqli->query("SELECT `img_".$context."`, `title_".$context."`, `count` FROM `darvo_mods_wiki` WHERE `id`= '".$found['item_id']."'");
	if ($result->num_rows > 0) {
		while($row = $result->fetch_assoc()) {
			$item = $row;
		}
	}
	
	$item_maxcount = $item['count'];
	$item_count = $found['item_count'];
	
	switch($filter_mod_count){
		case 'full':
			if($item_count != $item_maxcount){ goto end_f; }
			break;
		case 'null':
			if($item_count != 0){ goto end_f; }
			break;
		default:
			break;
	}
	$item_type = $found['item_type'];

	//объявления с открытой ценой
		$item_price = $found['item_price'];
		if($found['item_price']==0){
			$item_price = 'ваша цена';
		}
		
	//Выведем кнопку удалить, если:
		if(($from_profile == 1)and($real_id == $user_id)){
			$btn_chat = $modx->GetChunk('btn_del',Array(
				'del_id' => $found['id']
			));
		}else{
			$btn_chat = $modx->GetChunk('btn_chat',Array(
				'item_type' => $item_type,
				'item_price' => $found['item_price'],
				'action' => $action,
			));
		}
	
	$SearchResultTableItems .= $modx->getChunk('result_table_items', Array(
		'action' => $action,
		'item_type' => $item_type,
		'status' => $status['status'],
		'status_color' => $status['color'],
		'user_id' => $user_id,
		'user_name' => $user_name,
		'item_id' => $found['item_id'],//для линка на страницу информации
		'item_count' => $item_count,
		'item_price' => $item_price,
		'item_img' => $item['img_'.$context],
		'item_name' => $item['title_'.$context],
		'item_maxcount' => $item_maxcount,
		'part_name' => $part_name['img_'.$context],
		'act_msg' => $act_msg,
		'btn_chat' => $btn_chat,
		'btn_del' => $btn_del,
		'number' => $number,
		'all' => 1,
	));

$number++;
end_f:
}

return_res:
$result = $mysqli->query("SELECT `title_".$context."` FROM `darvo_mods_wiki` WHERE `id`= '".$item_id."'");
if ($result->num_rows > 0) {
	while($row = $result->fetch_assoc()) {
		$item = $row;
	}
}

$SearchResultTableWrapper = $modx->getChunk('result_table_items_wrap', Array(
	'action' => $action,
	'item_name' => $item['title_'.$context],
	'SearchResultTableItems' => $SearchResultTableItems,
	'all' => 1,
	'ajax' => $ajax,
	'user_name' => $user_name,
	'user_id' => $user_id,
	'user_edit' => $user_edit,
	'from_profile' => $from_profile,
));

mysqli_close($mysqli);
return $SearchResultTableWrapper;
Чанк «result_table_items» данные таблицы:
<tr class="[[!+status]]">
<!--<td>[[$icons-sell]]</td>-->
<td class="hidden-xs hidden-sm col-sm-1 col-md-1 text-center"><label>[[+number]]</label></td>
<td class="col-xs-3 col-sm-5 col-md-3 text-left">[[+item_type:is=`mod`:then=`[[+item_count]]/[[+item_maxcount]]`:else=``]] <a href="item/[[+item_id]]/">[[+item_name]]</a></td>
<td class="col-xs-1 col-sm-1 col-md-1 text-center [[+action:is=`trade`:then=`hidden`:else=``]]">[[+item_price]]</td>
<td class="col-xs-2 col-sm-2 col-md-2 text-center"><a href="/users/[[+user_id]]/" title="[[-+region]]ru" style="color:[[!+status_color]]">[[+user_name]]</a></td>
<td class="hidden-sm hidden-xs text-center">[[+btn_chat]]
</td>
</tr>
Чанк «result_table_items_wrap» заголовок таблицы + фильтры:
[[+ajax:is=`1`:then=``:else=`[[+all:is=`1`:then=`<div class="form-inline">
<div class="form-group">
<select id="action" class="searching form-control">
    <option value="buy">Куплю</option>
    <option value="sell">Продам</option>
</select>
</div>
<div class="form-group">
<select id="item_type" class="searching form-control">
    <option value="all">Все</option>
    <option value="mod">Только Моды</option>
    <option value="pack">Только Паки</option>
    <option value="item">Только Прайм части</option>
</select>
</div>
<div class="form-group">
<select id="status" class="searching form-control">
    <option value="online">Только Online</option>
    <option value="all">Все объявления</option>
</select>
</div>
</div>
<div id="search_result" style="position:relative">`:else=``]]`]]
<table id="myTable1" class="myTable table table-hover table-striped">
	<thead>
		<tr>
			<th class="hidden-xs hidden-sm col-sm-1 col-md-1 text-center"><label>№</label></td>
			<th class="col-xs-3 col-sm-5 col-md-3 text-left"><label>Предмет</label></th>
			<th class="col-xs-1 col-sm-1 col-md-1 text-center">
			<label class="hidden-sm hidden-xs">Стоимость</label><label><img src="img/favicon.ico"></label>
			</th>
			<th class="col-xs-1 col-sm-1 col-md-1 text-center [[+item_type_to:is=`mod`:then=``:else=`hidden`]]">
			<label>Ранг</label>
			</th>
			<th class="col-xs-2 col-sm-2 col-md-2 text-center"><label>Игрок</label></th>
			<th class="col-xs-2 col-sm-1 text-center hidden"><label>Статус</label></th>
			<th class="hidden-sm hidden-xs col-md-1 text-center"><label>Связь</label></th>
		</tr>
	</thead>
	[[+SearchResultTableItems]]
	</table>
[[+ajax:is=`1`:then=``:else=`[[+all:is=`1`:then=`</div>
<script>
$(document).ready(function(){
	$('.searching').change(function(){
		search_items($('#action').val(),$('#item_type').val(),$('#status').val());
		//console.log($('#item_type').val()+','+$('#action').val());
		return false;
	});
[[+from_profile:is=`1`:then=`$('.del').click(function(){
		act = 'del_'+$('#action').val();
		var $btn = $(this);
		console.log($btn.closest('tr'));
			$.ajax({
				headers: {'X-Requested-With': 'XMLHttpRequest'},
				method: "POST",
				url: "[[~307]]",
				datatype: "json",
				data: { 'action': act, 'action_id': $btn.attr('alt') },
				beforeSend: function() {
					$('#search_result').append('<div id="loading" style="position: absolute;  top: 0px;  left: 0px;  width: 100%;  height: 100%;  background-color: rgba(255,255,255,0.5);"><div style="margin: 0 auto;  background: url(img/misc/ajaxloader.gif?1) no-repeat; background-size: contain; width: 128px;  height: 128px;"></div></div>');
				}
			})
			.done( function( data ) {
				$('#loading').remove();
				if(data == 'err'){
					alert('Что-то пошло не так. Обратитесь к администратору.');
				}else{
					$btn.closest("tr").addClass('hide');
				}
			})
			.fail( function( data ) {
				alert('Что-то пошло не так. Обратитесь к администратору.');
			});
		});`:else=``]]
});

function search_items(action,item_type,status){
	$.ajax({
		headers: {'X-Requested-With': 'XMLHttpRequest'},
		method: "POST",
		url: '[[~320]]',
		datatype: "html",
		data: {action: action, item_type: item_type, status: status, context: '[[*context_key]]', user_name: '[[+user_name]]', from_profile: '[[+from_profile]]', user_id: '[[+user_id]]'},
		beforeSend: function(){
			$('#search_result').append('<div id="loading" style="position: absolute;  top: 0px;  left: 0px;  width: 100%;  height: 100%;  background-color: rgba(255,255,255,0.5);"><div style="margin: 0 auto;  background: url(img/misc/ajaxloader.gif?1) no-repeat; background-size: contain; width: 128px;  height: 128px;"></div></div>');
		}
	})
	.done( function(data) {
		$('#search_result').html(data);
		
		var client = new ZeroClipboard($(".btn-copy"), {
		  moviePath: "//uzerbar.ru/plugins/zclip/ZeroClipboard.swf"
		});

		client.on("load", function(client1) {  
		  client.on("complete", function(client, args) {
			$('.btn-copy').hide(); // скрываем для наглядности кнопку
		  });
		});
[[+from_profile:is=`1`:then=`$('.del').unbind();
$('.del').click(function(){
		act = 'del_'+$('#action').val();
		var $btn = $(this);
		console.log($btn.closest('tr'));
			$.ajax({
				headers: {'X-Requested-With': 'XMLHttpRequest'},
				method: "POST",
				url: "[[~307]]",
				datatype: "json",
				data: { 'action': act, 'action_id': $btn.attr('alt') },
				beforeSend: function() {
					$('#search_result').append('<div id="loading" style="position: absolute;  top: 0px;  left: 0px;  width: 100%;  height: 100%;  background-color: rgba(255,255,255,0.5);"><div style="margin: 0 auto;  background: url(img/misc/ajaxloader.gif?1) no-repeat; background-size: contain; width: 128px;  height: 128px;"></div></div>');
				}
			})
			.done( function( data ) {
				$('#loading').remove();
				if(data == 'err'){
					alert('Что-то пошло не так. Обратитесь к администратору.');
				}else{
					$btn.closest("tr").addClass('hide');
				}
			})
			.fail( function( data ) {
				alert('Что-то пошло не так. Обратитесь к администратору.');
			});
		});`:else=``]]
	})
	.fail( function() {
		alert('Что-то пошло не так. Обратитесь к администратору.');
	});
}
</script>`:else=``]]`]]
Пытался так сделать, и наконец-то что-то начало получаться!
Моя ошибка в том, что я считал что передавать нужно обычный массив со значениями. Что затем, pdoPage подставит значения в нужный чанк, где это нужно. Ведь это быстрее? Чем загружать уйму лишнего HTML кода? Это мне казалось логичным, т.к. нечто подобное видел в прочих сниппетах, аля регистрация и т.д.

В действительности же, нужно передавать массив, состоящий из чанков заполненными данными. Какой же у меня был фейспалм… Я снова заблуждаюсь?


Вопрос. Из-за Ajax передачи значений переменных сниппету, думаю, что желательно запускать pdoPage прямо внутри сниппета. Такое возможно?
Но вот если бы вам для одного пользователя нужно было бы слать несколько запросов на один и тот же домен (скажем, сперва авторизовать, потом отправить какие-то данные, потом получить данные с какой-то другой страницы от имени этого авторизованного юзера) и всё это в рамках одного php-процесса и подряд — то да, в keep-alive был бы смысл. Ибо на все эти три запроса не было бы повторных соединений, потому что curl держал бы лишь одно.
По сути так и есть, я логинюсь по 1 ссылке, парсю страницу по 2, и отправляю сообщение по 3.

А поскольку вы уверены в немощности вашего vps, значит (скорей всего) нет у вас на сайте такого количества одновременных пользователей и последний вариант — самый вероятный :)
Простите, перепутал с Shared. У меня почему-то ассоциация V — virtual — и значит слабый.
Именно с Шаред переходил на ВПС, с ростом аудитории.

Текущий проект лежит на шаред, на этапе разработки намного выгоднее держать именно Шаред (на своем компе не держу по некоторым причинам). И присутствует мандраж, что на этапе раскрутки, начнутся тормоза на Шареде.

Впрочем, оставил все как есть, судя по всему не так сильно и грузит, как ни странно уходит около 3 секунд на запрос, что практически не заметно, глядя на ajaxloader.

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