Как стать автором
Обновить

Генерация html на PHP

Время на прочтение2 мин
Количество просмотров23K
Предлагаю вашему вниманию свое решение по генерации html на PHP. Задача вроде бы тривиальная, но хотелось бы, чтобы это было расширяемо, кратко, но в тоже время с хорошим функционалом. Получилось вроде не плохо.

Сразу скажу( как многие считают в комментариях), что задача ставилось не написать шаблонизатор (которых и так много) и не заменить шаблонизатор JavaScript. Я прекрасно знаю, что true way это разделять html и данные. Но мне понадобилось писать html в классах, для создания компонентов фреймворка, на подобие CGridView в yii, стоит ли в таких местах выносить html в отдельные файлы решать вам.

Основная цель, избавится от html в классах и функциях.

Простой пример, обычная кнопка:

CHtml::create()
    ->p()
        ->a(array('href' => 'http://habrahabr.ru', 'class' => 'btn'))
            ->text('Перейти')
    ->render();

Результат:

<p><a href="http://habrahabr.ru" class="btn">Перейти</a></p>



Ничего хитрого, можно было бы этим и ограничется, но захотелось циклы:

$arr = array('1' => 'Первый', '2' => 'Второй');

CHtml::create()
	 ->select($options)
		->each(CHtml::plainArray($arr, 'value', 'text'))
			->option('array("value" => $data->value)')
				 ->text('$data->text')
		->end()
	->endEach()


Тут понадобилось вызвать функцию plainArray() которая превращает массив в виде:
$arr = array(
    array('value' => '1', 'text' =>'Первый'), 
    array('value' => '2', 'text' => 'Второй')
);

Теги внутри цикла могут содержать функции или строки с eval выражениями, вложенность любая, пример с таблицей:

$columns = array(
    array('id' => 'NAME', 'label' => 'Имя'),
    array('id' => 'AGE', 'label' => 'Возраст')
);

$data = array(
    array('NAME' => 'Петр', 'AGE' => 29),
    array('NAME' => 'Василий', 'AGE' => 32)
);

CHtml::create()
	->table()
		->thead()
			 ->tr()
			->each($columns)
				 ->th()
					->text(function($column){
						 return $column['label'];
					})
                                 ->end()
			->endEach()
 			->end()
		->end()
			->tbody()
			->each($data)
				->tr()
				->each($columns)
					->td()
						->text(function($row, $column) {
	                                              return $row[$column['id']];
						})
					->end()
				->endEach()
				->end()
			->endEach()
->render();


Незакрытые теги закрываются автоматически.

Класс можно расширить, вплоть до использования в формах. Расширить можно за счет наследования или внедрения зависимости, за то, как будет выводится каждый тег и его атрибуты используется одна функция, поэтому можно легко переопределить это поведение.


class CMyHtml extends CHtml {

	public function a($options = array()) {
		$default = array(
			'href' => 'javascript:void(0)'
		);
		return parent::a(array_replace($default, $options));
	}
}



class CForm {
        
        private $_lastLabel = '';
	public function __construct(CModel $model, CHtml $html = null) {
		$this->_model = $model;
		$this->_html = $html ?: CHtml::create();
	}

	public function __call($method, $ps) {
		$options = $ps ? $ps[0]: array();

		if ($method === 'label') {
			$this->_lastLabel = isset($options['for']) ? $this->_model->getLabel($options['for']) : '';
		}

		if ($method === 'text' && $this->_lastLabel) {
			$options = $options ?: $this->_lastLabel;
			$this->_lastLabel = '';
		}
               $this->_html->$method($options);
	       return $this;
       }
}


Само решение можно посмотреть и попробовать на github.

Спасибо за внимание.
Теги:
Хабы:
-29
Комментарии88

Публикации

Истории

Работа

PHP программист
158 вакансий

Ближайшие события