Zend Framework: XSL and self-serializing Views
article Translation Zend Framework: XSL and self-serializing Views
Author: Pascal Opitz
I have long argued that framwork MVC needs to use XSL style sheets instead of inline PHP code and other things. That's why I knocked together a little proof of concept of the Zend Framework, where representations of files in the XSL template and the submission serializes itself into XML for rendering.
the
I just created a demo layout using the standard MVC Zend_Controller from:
Of course, now we need a bootstrap file:
the
Please note that I introduced a new viewRenderer and the object that is called from View_Xslt.php and is located in the library folder/demo. Also I set the suffix of the view for the XSL.
ZIP file containing all the demo (excluding the Zend Framework files) can be downloaded here.
View object must be derived from a class that extends Zend_View_Abstract. Rending of View occurs in the _run method, the view file will be passed as the first argument. However, this argument needs to be accessed with func_get_arg, otherwise we are faced with a neat error message that our application is incompatible with Zend_View_Abstract.
To my View object self-serializing later, I also added the Serializer in the constructor magic method, plus I added a private function that serializes the submission in XML using the Serializer which we just created.
the
So what is this serializer does? It uses Reflection(reflection) functionality to serialize objects to XML string. This enables us to use the normal variables to view with our action controllers(controller actions), just put $this->foo = 'bар'.
I did a quick post XML Serialization in the past, and the Serializer I have presented is inspired by what I found there. Caution: Keep in mind that this is just a proof of concept, and to get the best results, it probably requires a little more work.
the
Almost all of them. We just need some XSL file and controller action to get a running demo. First the controller and action. I have included a small demo class, so we could see the serializer in action:
the
File(s) View. We could only create one, but because I wanted to support Zend_Layout, I didn't use xsl: import in order to do something like that.
the
the
And that's it! The resulting index page should give you output something like this:
the
It so happened that I've been working with XML and I wanted to use from the XSLT template engine in Zend framework, and this is the only article I could find that allows you to realize this wish.
In the result, I got a simple system where the engine and a set of standard templates worked for a small business cards websites and content from them is stored in xml files the data folder. And the whole migration from hosting to hosting was simply copying, without the headache DB. And the published folder only contain CSS, JavaScript and images.
Article based on information from habrahabr.ru
Author: Pascal Opitz
I have long argued that framwork MVC needs to use XSL style sheets instead of inline PHP code and other things. That's why I knocked together a little proof of concept of the Zend Framework, where representations of files in the XSL template and the submission serializes itself into XML for rendering.
the
the basic structure of the MVC
I just created a demo layout using the standard MVC Zend_Controller from:
|-application
|---default
|----- controllers
|----- models
|----- views
|------- filters
|------- helpers
|------- scripts
|---------index
|---------test
|-library
|---demo
|---zendframework_1.6.2
|-webroot
Of course, now we need a bootstrap file:
the
set_include_path('.'
. PATH_SEPARATOR . '../library/zendframework_1.6.2/'
. PATH_SEPARATOR . '../library/demo/'
. PATH_SEPARATOR . '../application/default/controllers'
. PATH_SEPARATOR . get_include_path());
require_once('Zend/Loader.php');
Zend_Loader::loadClass('Zend_Controller_Front');
Zend_Loader::loadClass('Zend_Controller_Action_Helper_Viewrenderer');
$frontController = Zend_Controller_Front::getInstance();
$frontController- > setControllerDirectory(array(
'default' => '../application/default/controllers',
));
require_once 'View_Xslt.php';
$view = new View_Xslt;
$options = array();
$viewRenderer = new Zend_Controller_Action_Helper_Viewrenderer($view, $options);
$viewRenderer- > setViewSuffix('xsl');
Zend_Controller_Action_HelperBroker::addHelper($viewRenderer);
$frontController->dispatch();
Please note that I introduced a new viewRenderer and the object that is called from View_Xslt.php and is located in the library folder/demo. Also I set the suffix of the view for the XSL.
ZIP file containing all the demo (excluding the Zend Framework files) can be downloaded here.
Views (VIEW)
View object must be derived from a class that extends Zend_View_Abstract. Rending of View occurs in the _run method, the view file will be passed as the first argument. However, this argument needs to be accessed with func_get_arg, otherwise we are faced with a neat error message that our application is incompatible with Zend_View_Abstract.
To my View object self-serializing later, I also added the Serializer in the constructor magic method, plus I added a private function that serializes the submission in XML using the Serializer which we just created.
the
require_once('Serializer.php');
class View_Xslt extends Zend_View_Abstract
{
private $serializer;
private $rootName;
public function __construct($data = array()) {
$this- > serializer = new Serializer();
parent::__construct($data);
}
public function setRootName($name) {
$this- > rootName = $name;
}
protected function _run() {
$template = func_get_arg(0);
$xslDoc = new DOMDocument();
$xslDoc- > load($template);
$xmlDoc = $this->toXml();
$proc = new XSLTProcessor();
$proc- > importStylesheet($xslDoc);
echo $proc- > transformToXML($xmlDoc);
}
private function toXml() {
$xml_str = $this- > serializer- > Serialize($this, $this- > rootName);
return $xml_str;
}
}
Serializer (Serializer)
So what is this serializer does? It uses Reflection(reflection) functionality to serialize objects to XML string. This enables us to use the normal variables to view with our action controllers(controller actions), just put $this->foo = 'bар'.
I did a quick post XML Serialization in the past, and the Serializer I have presented is inspired by what I found there. Caution: Keep in mind that this is just a proof of concept, and to get the best results, it probably requires a little more work.
the
class Serializer
{
private $xmlDoc;
public function __construct() {
$this->xmlDoc = new DOMDocument();
}
public function Serialize($inst, $nodeName=null) {
if(is_object($inst))
{
$nodeName = ($nodeName == null) ? get_class($inst) : $nodeName;
$root = $this->xmlDoc->createElement($nodeName);
$this->xmlDoc->appendChild($root);
$this- > SerializeObject($inst, $nodeName, $root);
} else if(is_array($inst)) {
$nodeName = ($nodeName == null) ? get_class($inst) : $nodeName;
$root = $this->xmlDoc->createElement($nodeName);
$this->xmlDoc->appendChild($root);
$this- > SerializeArray($inst, $nodeName, $root);
}
return $this- > xmlDoc;
}
private function SerializeObject($inst, $nodeName, $parent) {
$obj = new ReflectionObject($inst);
$properties = $obj->getProperties();
foreach($properties as $prop) {
if(!$prop- > isPrivate()) {
$elem = $this- > SerializeData($prop- > getName(), $prop- > getValue($inst), $parent);
}
}
}
private function SerializeArray($array, $nodeName, $parent) {
foreach($array as $key => $val) {
$keyStr = (is_numeric($key)) ? 'There' : $key;
if(is_numeric($key)) {
$elem->setAttribute('index', $key);
}
}
}
private function SerializeData($key, $val, $parent) {
if(is_object($val)) {
$propNodeName = get_class($val);
$elem = $this->xmlDoc->createElement($propNodeName);
$parent->appendChild($elem);
$this- > SerializeObject($val, $propNodeName, $parent);
$elem->setAttribute('type', 'object');
} else if(is_array($val)) {
$elem = $this->xmlDoc->createElement($key);
$parent->appendChild($elem);
$this- > SerializeArray($val, $key, $elem);
$elem->setAttribute('type', 'array');
} else {
$elem = $this->xmlDoc->createElement($key, $val);
$parent->appendChild($elem);
$elem->setAttribute('type', 'property');
}
return $elem;
}
}
Files of the Controller, and Views
Almost all of them. We just need some XSL file and controller action to get a running demo. First the controller and action. I have included a small demo class, so we could see the serializer in action:
the
class IndexController extends Zend_Controller_Action {
public function indexAction() {
$this->view->setRootName('DataObject');
$this->view->foo = 'bar';
$this->view->super = array(
'here' => 'there', 'foo' => array(1,2,'test'),
);
$this->view->testObject = new DemoObject();
$this->view->testObject- > var = 'testObjectVar';
}
}
class DemoObject {}
File(s) View. We could only create one, but because I wanted to support Zend_Layout, I didn't use xsl: import in order to do something like that.
the
<?xml version="1.0" encoding="ISO-8859-1"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:import href="../layout.xsl"/>
<xsl:template match="DataObject">
<xsl:apply-templates select="*" />
</xsl:template>
<xsl:template match="*">
<div>
<h2><xsl:value-of select="name()" /></h2>
<xsl:apply-templates select="text()" />
<xsl:apply-templates select="*" />
</div>
</xsl:template>
</xsl:stylesheet>
the
<?xml version="1.0" encoding="ISO-8859-1"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" encoding="ISO-8859-1" omit-xml-declaration="no" doctype-public="-//W3C//DTD XHTML 1.0 Transitional//EN" doctype-system="http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd" indent="yes" />
<xsl:template match="/">
<html>
<head>
<title>Test</title>
</head>
<body>
<xsl:apply-templates select="/*" />
</body>
</html>
</xsl:template>
</xsl:stylesheet>
Result
And that's it! The resulting index page should give you output something like this:
the
<?xml version="1.0" encoding="ISO-8859-1"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1" />
<title>Test</title>
</head>
<body>
<div><h2>foo</h2>bar</div>
<div>
<h2>super</h2>
<div><h2>here</h2>there</div>
<div>
<h2>foo</h2>
<div><h2>There</h2>1</div>
<div><h2>There</h2>2</div>
<div><h2>There</h2>test</div>
</div>
</div>
<div>
<h2>DemoObject</h2>
</div>
<div><h2>var</h2>testObjectVar</div>
</body>
</html>
It so happened that I've been working with XML and I wanted to use from the XSLT template engine in Zend framework, and this is the only article I could find that allows you to realize this wish.
In the result, I got a simple system where the engine and a set of standard templates worked for a small business cards websites and content from them is stored in xml files the data folder. And the whole migration from hosting to hosting was simply copying, without the headache DB. And the published folder only contain CSS, JavaScript and images.
Комментарии
Отправить комментарий