Владимир

Владимир

С нами с 28 декабря 2012; Место в рейтинге пользователей: #90
Василий Наумкин
03 декабря 2015, 20:20
2
0
Ну естественно, это мега-тайна, что все ТВ выбираются с префиксом tv. по умолчанию. В документации прям нет этого параметра. includeTVs, prepareTVs, processTVs и дальше пустота.

Можно и не делать пустой &tvPrefix, но тогда, не поверишь, нужно выводить ТВ вот так:
[[+tv.name]] - MODX
{$_pls['tv.name']} - Fenom
Про вывод через точку я тебе давал ссылку еще 2 часа назад.

А вообще, можно увидеть все плейсхолдеры, если просто не указывать чанк.
Павел Гвоздь
02 декабря 2015, 13:22
1
+1
У тебя помоему тут в таблице ТВшек хранится лишняя информация? В статье от Николая с подобной штукой был плагин, который удаляет лишнюю инфу из таблицы с ТВхами. Я его немного переписал. Вот, если кому надо:
<?php
/*
	OnBeforeDocFormSave
	OnDocFormSave
	OnResourceTVFormRender
*/

$tvs = array(
	2	=> "image",
	3	=> "city",
	4	=> "company",
	5	=> "email",
);

switch($modx->event->name)
{
	/* >> Рендеринг ТВшек */
	case 'OnResourceTVFormRender':
		
		if( !$document = $modx->getObject('modResource', $resource) )
		{
			$modx->log(xPDO::LOG_LEVEL_ERROR, "Не был получен документ");
			return;
		}
		
		$categories = & $scriptProperties['categories'];
		
		foreach( $categories as $c_id => & $category )
		{
			foreach( $category['tvs'] as & $tv )
			{
				if( array_key_exists($tv->id, $tvs) )
				{
					$q = $modx->newQuery('modTemplateVar');
					$q->select( 'type' );
					$q->where( 'name = "'. $tvs[ $tv->id ] .'"' );
					$tv_type = $modx->getValue( $q->prepare() );
					unset($q);
					
					// >> Рендеринг тэгов
					if( $tv_type == 'tags' )
					{
						$q = $modx->newQuery('modResourceTag');
						$q->select(array(
							"GROUP_CONCAT(distinct tag_id) as tags",
						));
						$q->where(array(
							"resource_id" => $document->id,
						));
						$tags = $modx->getValue($q->prepare());
						$value = str_replace(",", "||", $tags);
						$tv->value = $value;
						$tv->relativeValue = $value;
						$inputForm = $tv->renderInput($document, array('value' => $tv->value));
						$tv->set('formElement', $inputForm);
					}
					// << Рендеринг тэгов
					
					
					// >> Рендеринг строковых ТВшек
					else if(
							$tv_type == 'autotag' ||
							$tv_type == 'tag' ||
							$tv_type == 'image' ||
							$tv_type == 'email' ||
							$tv_type == 'date' ||
							$tv_type == 'option' ||
							$tv_type == 'listbox-multiple' ||
							$tv_type == 'listbox' ||
							$tv_type == 'resourcelist' ||
							$tv_type == 'hidden' ||
							$tv_type == 'text' ||
							$tv_type == 'textarea' ||
							$tv_type == 'richtext' ||
							$tv_type == 'list-multiple-legacy' ||
							$tv_type == 'file' ||
							$tv_type == 'checkbox' ||
							$tv_type == 'number' ||
							$tv_type == 'migx'
					) {
						$tv->value = $document->$tvs[ $tv->id ];
						$tv->relativeValue = $tv->value;
						$inputForm = $tv->renderInput($document, array('value'=> $tv->value));
						$tv->set('formElement', $inputForm);
					}
					// << Рендеринг строковых ТВшек
					
					
					// >> Рендеринг массивных ТВшек
					else if(
							$tv_type == 'listbox-multiple'
					) {
						$tv_value_array = array_map( function($v){ return trim($v,':'); }, explode( '::', $document->$tvs[ $tv->id ] ) );
						$tv->value = $tv_value_array;
						$tv->relativeValue = $tv_value_array;
						$inputForm = $tv->renderInput($document, array('value' => $tv->value));
						$tv->set('formElement', $inputForm);
					}
					// << Рендеринг массивных ТВшек
				}
			}
		}
		
	break;
	/* << Рендеринг ТВшек */
	
	
	/* >> Перед сохранением документа */
	case 'OnBeforeDocFormSave':
		
		if( !$resource = & $scriptProperties['resource'] )
		{
			$modx->log(xPDO::LOG_LEVEL_ERROR, "Не был получен документ");
			return;
		}
		
		// >> получим список id ТВшек, с которыми будем работать
		$i=0;
		$tv_where='';
		foreach( $tvs as $id => $name )
		{
			$tv_where .= !$i ? '' : ' OR ';
			$tv_where .= 'name = "'. $name .'"';
			$i++;
		}
		unset($i); unset($id); unset($name);
		
		$q = $modx->newQuery('modTemplateVar');
		$q->select( 'id, type, name' );
		$q->where( $tv_where );
		$s = $q->prepare();
		$s->execute();
		$tv_rows = $s->fetchAll(PDO::FETCH_ASSOC);
		unset($q); unset($s);
		// << получим список id ТВшек, с которыми будем работать
		
		
		// >> Обрабатываем ТВшки
		foreach( $tv_rows as $tv_row )
		{
			$var = 'tv'. $tv_row['id'];
			
			if( isset( $resource->$var ) )
			{
				// >> теги
				if( $tv_row['type'] == 'tags' )
				{
					$tags = array();
					foreach( (array)$resource->Tags as $tag )
					{
						$tag->active = 0;
						$tags[ $tag->tag_id ] = $tag;
					}
					
					if( !empty($resource->$var) )
					{
						foreach( (array)$resource->$var as $tv_value )
						{
							if( $tv_value )
							{
								if( !empty($tags[ $tv_value ]) )
								{
									$tags[ $tv_value ]->active = 1;
								}
								else {
									$tags[ $tv_value ] = $modx->newObject('modResourceTag', array(
										"tag_id" => $tv_value,
									));
								}
							}
						}
					}
					
					$resource->Tags = $tags;
					
					$tags_ids = array();
					foreach( $resource->Tags as $tag )
					{
						if( $tag->active )
						{
							$tags_ids[] = $tag->tag_id;
						}
					}
					
					$resource->$tv_row['name'] = ( $tags_ids ? implode(",", $tags_ids) : NULL );
				}
				// << теги
				
				
				// >> картинки и другие строковые
				else if($tv_row['type'] == 'autotag' ||
						$tv_row['type'] == 'tag' ||
						$tv_row['type'] == 'image' ||
						$tv_row['type'] == 'email' ||
						$tv_row['type'] == 'date' ||
						$tv_row['type'] == 'option' ||
						$tv_row['type'] == 'listbox' ||
						$tv_row['type'] == 'resourcelist' ||
						$tv_row['type'] == 'hidden' ||
						$tv_row['type'] == 'text' ||
						$tv_row['type'] == 'textarea' ||
						$tv_row['type'] == 'richtext' ||
						$tv_row['type'] == 'file' ||
						$tv_row['type'] == 'number' ||
						$tv_row['type'] == 'migx'
				) {
					//print_r( $resource->$var );
					
					$resource->$tv_row['name'] = $resource->$var;
				}
				// << картинки и другие строковые
				
				
				// >> массивы
				else if($tv_row['type'] == 'listbox-multiple' ||
						$tv_row['type'] == 'list-multiple-legacy' ||
						$tv_row['type'] == 'checkbox'
				) {
					$resource->$tv_row['name'] = ( $resource->$var ? implode("||", $resource->$var) : NULL );
				}
				// << массивы
			}
		}
		// << Обрабатываем ТВшки
		
	break;
	/* << Перед сохранением документа */
	
	
	/* >> Сохранение документа */
	case 'OnDocFormSave':
		
		if( !$resource = & $scriptProperties['resource'] )
		{
			$modx->log(xPDO::LOG_LEVEL_ERROR, "Не был получен документ");
			return;
		}
		
		if($tvs)
		{
			$modx->removeCollection('modTemplateVarResource', array(
				'tmplvarid:in'	=> array_keys($tvs),
				'contentid'		=> $resource->id,
			));
			
			// Сбрасываем автоинкримент
			//$sql = "ALTER TABLE {$tv_table} auto_increment = 1";
			//$modx->prepare($sql)->execute();
		}
		
	break;
	/* << Сохранение документа */
}

В массиве $tvs инфа о ТВхах в таком виде: id => name.
Сергей Скат
01 декабря 2015, 14:56
2
+2
в общем если поле ТВ, нужно писать его с префиксом и без скобок, примерно так
[[!pdoResources?
                        &parents=`0`
			&includeTVs=`opinion_view`
                        &tpl=`standart_news_block`
                        &tplCondition=`tv.opinion_view`
                        &tplOperator=`==`
                        &conditionalTpls=`{"1":"first_opinion", "2":"second_opinion", "3":"standart_news_block"}`
                    ]]
Подсказал Володя , за что ему большое спасибо!
Алексей Карташов
24 ноября 2015, 20:08
2
+5
Я в ближайшие несколько месяцев буду писать фронтенд для одного крупного b2b-сервиса (бекендеры его делают на yii2, не modx). С кучей динамики — crud-таблицы, модалки, вот это всё.
Я очень много времени провёл в выборе адекватного фреймворка/библиотеки с двухсторонним дата-биндингом, отсутствием магии в исходниках, простоте в поддержке кода, и отсутствием навязывания структуры приложения.

Много чего смотрел — vue.js, riot.js, angular, react, ractive, rivets, mithril, куча их
plnkr.co/edit/leZaT043Yffz4LfG8Ykq

Так вот. Нахер ангуляр. Если вам кто-то рьяно советует брать ангуляр, то это либо очень хороший спец (каких действительно мало), либо ведомый на моду новичок (который не делал ничего сложнее примеров из туториалов). Причём очень хороший спец вряд ли будет вам его советовать, потому что он прекрасно знает сколько подводных камней может собрать неопытный разработчик. Писать на нём что-то серьёзное — это постоянная борьба с самим фреймворком (при условии отсутствия должного опыта). А набивать этот опыт — смысла тупо нет ибо сами авторы от своих подходов уже отказались и пилят новую версию с нуля вообще выбросив дата-биндинг со своим dirty-checking'ом.

Реакт можно брать и изучать только в том случае, если вас не воротит от адовой смеси html и типа-js (jsx). Меня лично воротит :-D

Та же история с riot — он прикольный, но для действительно сложных интерфейсов может не подойти. Та же адова смесь логики и вьюхи, но до кучи — каждый компонент должен лежать в отдельном изолированном tag-файле. Расширяемые насыщенные интерфейсы делать сложновато.

Vue — очень схожий с ангуляром в плане синтаксиса вьюх (если это вообще можно назвать вьюхами). Есть скринкаст, где парень за час написал на нём excel (прям с редактированием ячеек и формулами). Но если взглянуть на этот код через полгода, то хоть с бутылкой, хоть без неё — разобраться проблематично. В плане поддержки кода и вхождения в проект — не оч.

Rivets/ractive — всё туда же, но со своими приколами.

Лично для себя я выбрал (не поверите) матрёшку. Я приверженец выбранного автором матрёшки подхода — вьюхи отдельно, логика работы с вьюхами — отдельно. Из коробки двухсторонний дата-бинд без магии (на геттерах и сеттерах). Это то, чего мне так не хватало в любимом мною Backbone'е.
Структура приложения не навязывается — хочешь писать на «классах» — пиши, хочешь писать универсальные расширяемые ui-компоненты — пиши (если умеешь)). Шаблонизатор — бери любой по вкусу (я выбрал swig). Хочешь компилировать вьюхи на этапе сборки? Всё в твоих руках (привет ангуляр, vue, ractive).
Да, кода надо писать побольше, но зато он полностью под твоим контролем и в нём разберётся любой джуниор, миддл — тем более.

А если нету жёстких условий по интерфейсу и дизайну — берите ExtJS, используйте его обширную библиотеку готовых компонентов и не заморачивайтесь.

Как-то так.
Василий Наумкин
24 ноября 2015, 10:14
1
+2
ms2Gallery проверяет первые 8 килобайт изображения, видимо они действительно одинаковые.

Можно отключить эту проверку — создай системную настройку ms2gallery_duplicate_check и укажи там 0.
Василий Наумкин
22 ноября 2015, 16:37
3
0
Парсер MODX работает в цикле до 10 раз, чтобы разобрать все плейсхолдеры. То есть:
1. Видим [[+totalMy]], значения нет
2. Видим [[!getTickets]], запускаем, он выставляет значение
3. Проверяем, что у нас осталось необработанного
4. Запускаемся еще раз и вот теперь только обрабатываем [[+totalMy]]
5. Ой, а чего это у меня так всё тормозит?

Fenom работает один раз и позволяет сохранять работу сниппетов в переменные:
{set $tickets = $_modx->runSnippet('!getTickets', [
    'parents' => 0,
    'totalVar' => 'totalMy',
])}

{$_modx->getPlaceholder('totalMy')}

{$tickets}
Павел Романов
19 ноября 2015, 17:27
5
+4
Делаете два сниппета.

Первый sortLink:
<?php
if($_GET['sort'] == $field and $_GET['dir'] == 'ASC') {$arr='&_uarr;';}
if($_GET['sort'] == $field and $_GET['dir'] == 'DESC') {$arr='&_darr;';}
if(!$_GET[$field]){
	if($_GET['dir'] == 'ASC'){
		$output = '<a href="'.$url.'?'.$q.'sort='.$field.'&dir=DESC#prod">'.$name.''.$arr.'</a>';
	} else {
		$output = '<a href="'.$url.'?'.$q.'sort='.$field.'&dir=ASC#prod">'.$name.''.$arr.'</a>';
	}
} else {
	$output = '<a href="'.$url.'?'.$q.'sort='.$field.'&dir=ASC#prod">'.$name.'</a>';
}
return $output;
(во второй и третьей строке только уберите нижнее подчеркивание в &_uarr; и &_darr;)

Второй Sort:
<?php
$sort = $_GET['sort'];
if($sort == '') {
    $output='&sortby=`{"menuindex":"ASC"}`';
} else {
    $output = '&sortby=`{"'.$sort.'":"'.$_GET['dir'].'"}`';
}
return $output;

Используете так:
<div class="sort">
Сортировать: 
[[!sortLink? &url=`[[*uri]]` &field=`pagetitle` &name=`по названию`]]  
[[!sortLink? &url=`[[*uri]]` &field=`price` &name=`по цене`]]  
</div>
<div class="results">
[[!pdoResources?
&parents=`...`
&tpl=`...`
.........
[[!Sort]]
]]
</div>
Василий Наумкин
19 ноября 2015, 10:23
10
+7
My quick example:
<?php
$tplWrapper = '@INLINE <ul>{{+output}}</ul>';
$tplYear = '@INLINE <li>{{+year}}<sup>({{+count}})</sup><ul>{{+resources}}</ul></li>';
$tplMonth = '@INLINE <li>{{+month}}<sup>({{+count}})</sup><ul>{{+resources}}</ul></li>';
$tpl = '@INLINE <li><a href="{{+uri}}">{{+pagetitle}}</a></li>';

$pdo = $modx->getService('pdoFetch');

$resources = $pdo->getCollection(
	'modResource',
	array('published' => true, 'deleted' => false),
	array('parents' => 0, 'sortby' => 'createdon', 'sortdir' => 'DESC')
);
$tree = array();
foreach ($resources as $resource) {
	$year = date('Y', $resource['createdon']);
	$month = date('m', $resource['createdon']);
	$tree[$year][$month][] = $resource;
}

$output = '';
foreach ($tree as $year => $months) {
	$tmp1 = '';
	$count = 0;
	foreach ($months as $month => $resources) {
		$tmp2 = '';
		foreach ($resources as $resource) {
			$tmp2 .= $pdo->getChunk($tpl, $resource);
			$count++;
		}
		$tmp1 .=  $pdo->getChunk($tplMonth, array(
			'month' => $month,
			'count' => count($resources),
			'resources' => $tmp2,
		));
	}
	$output .=  $pdo->getChunk($tplYear, array(
		'year' => $year,
		'count' => $count,
		'resources' => $tmp1,
	));
}

return $pdo->getChunk($tplWrapper, array('output' => $output));

Result:
Василий Наумкин
16 ноября 2015, 10:26
1
0
{extends 'template:layout'}

{block 'wrapper'}
 	<!-- здесь будет расширение -->
{/block}
Не проверял, но уверен, что сработает.
Василий Столейков
11 ноября 2015, 08:44
1
+4
Набросал свой сниппет-модификатор user_info (чтобы легче было перейти с MODX-модификаторов) по примеру выше.
Вполне себе рабочее решение как мне кажется:
<?php
$output = '';
$profile = $modx->getObject('modUserProfile', ['internalKey' => $input]);
if($profile) {
    if (strpos($options,'extended.') === false) {
        $output = $profile->$options;
    } else {
        $ext = explode(".", $options);
        $profile = $profile->get('extended');
        if(isset($profile[$ext[1]])) {
            $output = $profile[$ext[1]];
        }        
    }    
}
return $output;
Вызываю его так:
{$_modx->runSnippet('!user_info', ['input' => 2,'options' => 'extended.skype'])}
где в options вбивается поле пользователя или extended-поле через точку.

Спасибо тебе, Гвоздь, и Василию за примеры и пинки в нужном направлении!