Предлагаю вашему вниманию свое решение по генерации html на PHP. Задача вроде бы тривиальная, но хотелось бы, чтобы это было расширяемо, кратко, но в тоже время с хорошим функционалом. Получилось вроде не плохо, чем и спешу поделиться.
Простой пример, обычная кнопка:
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.
Спасибо за внимание.
ссылка на оригинал статьи http://habrahabr.ru/post/270147/
Добавить комментарий