Деревья на нативном шаблонизаторе.

Lightning

Трудоголик
Деревья на нативном шаблонизаторе.

В качестве шаблонизатора используется PHP.
Необходимо сделать шаблоны, выводящие деревья. Как это по-нормальному реализовать, чтобы код шаблона выглядел достаточно понятно? Может у кого-нибудь есть такие шаблоны для примера?

Еще одна просьба: про XSLT и Smarty тут не писать, нужно использовать именно нативный шаблонизатор.
 

Lightning

Трудоголик
HraKK
Можно вывести дерево используя только foreach? Как?
foreach - для массивов.
 

HraKK

Мудак
Команда форума
отсортируй вложенную структуру перед выводом. или испоьзуй хелпер
 

fixxxer

К.О.
Партнер клуба
Хелпер это совершенно необязательно говно вида return '<li>..'.

У хелпера прекрасно может быть подшаблон.
 

Фанат

oncle terrible
Команда форума
вроде, по ссылке обсмотрели все варианты. можно просто выбрать наиболее подходящий лично для себя
 

Lightning

Трудоголик
вроде, по ссылке обсмотрели все варианты. можно просто выбрать наиболее подходящий лично для себя
Мне больше всего понравился вариант, который C. предложил. Но пока не могу понять, как он это смог реализовать без if, просто вложенным while.
 

Lightning

Трудоголик
Вроде мне не подходят варианты из соседнего топика. У меня ситуация усугубляется еще тем, что ветки и листья нужно различать.
Т.е. листья должны быть ссылками, а ветки просто текстом.
Пока что удалось реализовать такой вариант:
PHP:
<ul id="tree">
	<? Tree::init($tree, 'children') ?>
	<? while(Tree::get($item)) { ?>
		<? if(Tree::branch()) { ?>
			<li><div><?= $item['title'] ?></div>
				<ul>
		<? } elseif(Tree::leaf()) { ?>
					<li><a href="<?= $item['href'] ?>"><?= $item['title'] ?></a></li>
		<? } elseif(Tree::endbranch()) { ?>
				</ul>
			</li>
		<? } ?>
	<? } ?>
</ul>
Мне самому не нравится.
Один только плюс, что не приходится преобразовывать дерево в плоский список.
Хотелось бы чтобы структура шаблона была похоже на

PHP:
<ul id="tree">
	{tree}
		{branch}
			<li><div><?= $branch['title'] ?></div>
				<ul>
					{leaf}
						<li><a href="<?= $leaf['href'] ?>"><?= $leaf['title'] ?></a></li>
					{/leaf}
				</ul>
			</li>
		{/branch}
	{/tree}
</ul>
Автор оригинала: x-yuri
имхо, для деревьев естественна рекурсия
И что? Предлагаешь писать в шаблон функцию? Я пытаюсь сделать шаблон как можно понятней.
 

x-yuri

Новичок
И что? Предлагаешь писать в шаблон функцию? Я пытаюсь сделать шаблон как можно понятней
понятность твоей цели весьма сомнительна:
http://community.livejournal.com/ru_php/789059.html
http://brodyaga.habrahabr.ru/blog/30767/
ну и эту тогда - http://habrahabr.ru/blogs/php/27999/ (к спорам о разделении html и php)

предложил бы что-то типа (pure PHP вариант)
PHP:
function show_tree( $tree ) {

    if (! count($tree['children']))
        return;

    ?><ul>
        <?php foreach( $tree['items'] as $item ) { ?>
			<li>
                <?php if( isset($item['items']) ) { ?>
                    <div><?php echo $item['title'] ?></div>
                    <?php show_tree( $item ) ?>
                <?php } else { ?>
                    <a href="<?php echo $item['href'] ?>"><?php echo $item['title'] ?></a>
                <?php } ?>
        <?php } ?>
    </ul><?php
}
 

С.

Продвинутый новичок
-----------------------------------------------------------------
ВАРИАНТ 1 (for)
-----------------------------------------------------------------
PHP:
<?

function tree($data=false,$key=false)
{
  static $pass,$hash;

  if ($data)
  {
    $hash=array();
    _tree_hash($data,$key,$hash);
    $pass=11;
    reset($hash);
  }
  $item= current($hash);

  if ($pass==11)
  {
    $pass=12;
  }
  elseif ($pass==12)
  {
    if ($item===false) return $hash=false;
    if ($item[0]!='open') ob_start();
    $pass=21;
    return true;
  }
  elseif ($pass==21)
  {
    if ($item[0]!='open') ob_end_clean();
    $pass=221;
  }
  elseif ($pass==221)
  {
    if ($item[0]=='branch')
    {
      $pass=23;
      return true;
    }
    else
    {
      if ($item[0]!='close') ob_start();
      $pass=13;
      return false;
    }
  }
  elseif ($pass==23)
  {
    $pass=222;
  }
  elseif ($pass==13)
  {
    if ($item[0]!='close') ob_end_clean();
    $item= next($hash);
    $pass=12;
  }
  elseif ($pass==222)
  {
    if ($item[0]!='close') ob_start();
    $pass=13;
    return false;
  }

  return $item[1];
}

function _tree_hash($data,$key,&$hash)
{
  $hash[]=array('open',NULL);
  foreach ($data as $branch)
  {
    $hash[]=array('branch',$branch);
    if (isset($branch[$key]) && count($branch[$key])>0) _tree_hash($branch[$key],$key,$hash);
  }
  $hash[]=array('close',NULL);
}

$treedata=array(
  array('id'=>'1'),
  array('id'=>'2'),
  array('id'=>'3','children'=>array(
    array('id'=>'3.1'),
    array('id'=>'3.2','children'=>array(
      array('id'=>'3.3.1'),
      array('id'=>'3.3.2'),
    )),
    array('id'=>'3.4'),
  )),
  array('id'=>'4'),
);

?>

<div>---------- Here the tree begins ----------</div>
<? for(tree($treedata,'children');tree();tree()): ?>
  <ul>
  <? for($branch=tree();tree();tree()): ?>
    <li><?=$branch['id']?></li>
  <? endfor ?>
  </ul>
<? endfor ?>
<div>---------- Here it ends ----------</div>
-----------------------------------------------------------------
ВАРИАНТ 2 (while)
-----------------------------------------------------------------

PHP:
<?

function wtree($data=false,$key=false)
{
  static $pass,$hash=false;

  if (!$hash)
  {
    $hash=array();
    _tree_hash($data,$key,$hash);
    $pass=11;
    reset($hash);
  }
  $item= current($hash);

  if ($pass==11)
  {
    if ($item[0]!='open') ob_start();
    $pass=21;
    return true;
  }
  elseif ($pass==21)
  {
    if ($item[0]!='open') ob_end_clean();
    if ($item[0]=='branch')
    {
      $pass=22;
      return $item[1];
    }
    else
    {
      if ($item[0]!='close') ob_start();
      $pass=12;
      return false;
    }
  }
  elseif ($pass==22)
  {
    if ($item[0]!='close') ob_start();
    $pass=12;
    return false;
  }
  elseif ($pass==12)
  {
    if ($item[0]!='close') ob_end_clean();
    $item= next($hash);
    if ($item===false) return $hash=false;
    if ($item[0]!='open') ob_start();
    $pass=21;
    return true;
  }
}

function _tree_hash($data,$key,&$hash)
{
  $hash[]=array('open',NULL);
  foreach ($data as $branch)
  {
    $hash[]=array('branch',$branch);
    if (isset($branch[$key]) && count($branch[$key])>0) _tree_hash($branch[$key],$key,$hash);
  }
  $hash[]=array('close',NULL);
}

$treedata=array(
  array('id'=>'1'),
  array('id'=>'2'),
  array('id'=>'3','children'=>array(
    array('id'=>'3.1'),
    array('id'=>'3.2','children'=>array(
      array('id'=>'3.3.1'),
      array('id'=>'3.3.2'),
    )),
    array('id'=>'3.4'),
  )),
  array('id'=>'4'),
);

?>

<div>---------- Here the tree begins ----------</div>
<? while(wtree($treedata,'children')): ?>
  <ul>
  <? while($branch=wtree()): ?>
    <li><?=$branch['id']?></li>
  <? endwhile ?>
  </ul>
<? endwhile ?>
<div>---------- Here it ends ----------</div>
 

Lightning

Трудоголик
понятность твоей цели весьма сомнительна:
http://community.livejournal.com/ru_php/789059.html
http://brodyaga.habrahabr.ru/blog/30767/
ну и эту тогда - http://habrahabr.ru/blogs/php/27999/ (к спорам о разделении html и php)

предложил бы что-то типа (pure PHP вариант)
Т.е. ты хочешь сказать, что нужно вываливать всю логику представления прямо в шаблон, не создавая никаких вспомогательных функций и классов вне шаблона?
Возможно, это с какой-то стороны и правильно, но
function show_tree( $tree ) {

if (! count($tree['children']))
return;

?><ul>
<?php foreach( $tree['items'] as $item ) { ?>
<li>
<?php if( isset($item['items']) ) { ?>
<div><?php echo $item['title'] ?></div>
<?php show_tree( $item ) ?>
<?php } else { ?>
<a href="<?php echo $item['href'] ?>"><?php echo $item['title'] ?></a>
<?php } ?>
<?php } ?>
</ul><?php
}
это колбаса выглядит не очень наглядно для верстальщика с базовыми знаниями PHP. Кроме того, в каждом шаблоне с деревом придется создавать свою функцию. А если есть какой-то вспомогательный класс, то работа с деревьями в разных шаблонах унифицирована.

С.
Спасибо
 

x-yuri

Новичок
Т.е. ты хочешь сказать, что нужно вываливать всю логику представления прямо в шаблон, не создавая никаких вспомогательных функций и классов вне шаблона?
Возможно, это с какой-то стороны и правильно, но
я скорее про то, что твоя цель похожа на блочный шаблон, в которых не вижу преимуществ кроме "не пугает верстальщика", зато вижу недостатки
а я просто привел пример в случае отсутствия шаблонизатора. Т.е. это просто идея, а ты уже можешь воспользоваться возможностями какого-то конкретного шаблонизатора
 

Lightning

Трудоголик
я скорее про то, что твоя цель похожа на блочный шаблон
Нет, ты не прав, я не хочу сделать блочный шаблон. В приведенном мной шаблоне видно, что выводится именно дерево (написано Tree::branch(), Tree::leaf() ...). А в блочных шаблонах нет различия между циклами, ветвлениями, деревьми и т.д.
 

x-yuri

Новичок
Хотелось бы чтобы структура шаблона была похоже на


<ul id="tree">
{tree}
{branch}
<li><div><?= $branch['title'] ?></div>
<ul>
{leaf}
<li><a href="<?= $leaf['href'] ?>"><?= $leaf['title'] ?></a></li>
{/leaf}
</ul>
</li>
{/branch}
{/tree}
</ul>
похоже я тебя неправильно понял (
 

Lightning

Трудоголик
Автор оригинала: x-yuri
похоже я тебя неправильно понял (
Похоже, что да.
Попытаюсь объяснить, что я имел ввиду под "Хотелось бы чтобы структура шаблона была похоже на ...".
Например, если представить, что в PHP есть специальная конструкция для обхода деревьев :) и шаблон можно было бы сделать так:
PHP:
<div>
<ul id="tree">
	<? fortree($tree) { ?>
		<? branch($branch) { ?>
			<li><div><?= $branch['title'] ?></div>
				<ul>
					<? leaf($leaf){ ?>
						<li><a href="<?= $leaf['href'] ?>"><?= $leaf['title'] ?></a></li>
					<? } ?>
				</ul>
			</li>
		<? } ?>
	<? } ?>
</ul>
</div>
Но в PHP не существует таких конструкций :) Поэтому хотелось бы сделать просто нечто похожее.
 

nerezus

Вселенский отказник
это колбаса выглядит не очень наглядно для верстальщика с базовыми знаниями PHP.
+ 1. Тоже непонятно, зачем short tags не используется. С ними все бкдкт очень понятно.
 
Сверху