PHP html generation

I bring to your attention my solution for generating html in PHP. The task seems to be trivial, but I would like it to be extensible, concise, but at the same time with good functionality. It turned out not so bad.

I must say right away (as many people think in the comments) that the task was not to write a template engine (there are so many) and not replace the JavaScript template engine. I know very well that the true way is to separate html and data. But I needed to write html in classes to create the components of the framework, similar to CGridView in yii, is it worth you to put html in separate files in such places.

The main goal is to get rid of html in classes and functions.

A simple example, a regular button:

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

Result:

Перейти



Nothing tricky, it could have been limited to this, but I wanted cycles:

$arr = array('1' => 'Первый', '2' => 'Второй');
CHtml::create()
	 ->select($options)
		->each(CHtml::plainArray($arr, 'value', 'text'))
			->option('array("value" => $data->value)')
				 ->text('$data->text')
		->end()
	->endEach()

Here it was necessary to call the plainArray () function which turns the array into the form:
$arr = array(
    array('value' => '1', 'text' =>'Первый'), 
    array('value' => '2', 'text' => 'Второй')
);

Tags inside a loop can contain functions or strings with eval expressions, any nesting, an example with a table:

$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();


Unclosed tags are closed automatically.

The class can be extended up to use in forms. You can expand it by inheriting or introducing a dependency, for how each tag will be displayed and its attributes, one function is used, so you can easily override this behavior.


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;
       }
}


The solution itself can be viewed and tried on github .

Thanks for attention.

Also popular now: