symphony/lib/toolkit/class.devkit.php
<?php
/**
* @package toolkit
*/
/**
* Devkit extends the HTMLPage class to provide an object representation
* of a Symphony Devkit page. Devkit's are used to aid in debugging by providing
* raw XML representations of data sources and parameters and to help provide
* profiling. There are two Symphony Devkit's currently, Debug and Profile. Devkit
* pages are restricted to Symphony Author's and require them to be authenticated
* to view them.
*/
class DevKit extends HTMLPage
{
/**
* The Devkit's `$_GET` query string
* @var string
*/
protected $_query_string = '';
/**
* An instance of the XSLTPage, usually FrontendPage
* @var XSLTPage
*/
protected $_page = null;
/**
* An associative array of the details of the Page that is being 'Devkitted'.
* The majority of this information is from `tbl_pages` table.
* @var array
*/
protected $_pagedata = null;
/**
* The XML of the page that the XSLT will be applied to, this includes any
* datasource results.
* @var string
*/
protected $_xml = null;
/**
* An array of the page parameters, including those provided by datasources.
* @var array
*/
protected $_param = array();
/**
* The resulting Page after it has been transformed, as a string. This is
* similar to what you would see if you 'view-sourced' a page in a web browser
* @var string
*/
protected $_output = '';
/**
* The title of the page
* @var string
*/
protected $_title;
/**
* Builds the Includes for a Devkit and sets the Content Type
* to be text/html. The default Symphony devkit stylesheet
* is the only include. The default doctype is enables HTML5
*/
protected function buildIncludes()
{
$this->addHeaderToPage('Content-Type', 'text/html; charset=UTF-8');
$this->Html->setElementStyle('html');
$this->Html->setDTD('<!DOCTYPE html>');
$this->Html->setAttribute('lang', Lang::get());
$this->addElementToHead(new XMLElement(
'meta',
null,
array(
'http-equiv' => 'Content-Type',
'content' => 'text/html; charset=UTF-8'
)
));
$this->addStylesheetToHead(ASSETS_URL . '/css/devkit.min.css', 'screen', null, false);
}
/**
* This function will build the `<title>` element and create a default
* `<h1>` with an anchor to this query string
*
* @param XMLElement $wrapper
* The parent `XMLElement` to add the header to
* @throws InvalidArgumentException
*/
protected function buildHeader(XMLElement $wrapper)
{
$this->setTitle(__(
'%1$s – %2$s – %3$s',
array(
$this->_pagedata['title'],
__($this->_title),
__('Symphony')
)
));
$h1 = new XMLElement('h1');
$h1->appendChild(Widget::Anchor($this->_pagedata['title'], ($this->_query_string ? '?' . trim(html_entity_decode($this->_query_string), '&') : '.')));
$wrapper->appendChild($h1);
}
/**
* Using DOMDocument, construct the Navigation list using the `devkit_navigation.xml`
* file in the `ASSETS` folder. The default navigation file is an empty `<navigation>`
* element. The `ManipulateDevKitNavigation` delegate allows extensions
* to inject items into the navigation. The navigation is build by iterating over `<item>`
* elements added. The idea is that all Devkit's can be accessed using the Navigation.
*
* @uses ManipulateDevKitNavigation
* @param XMLElement $wrapper
* The parent XMLElement to add the navigation to
* @throws InvalidArgumentException
*/
protected function buildNavigation(XMLElement $wrapper)
{
$xml = new DOMDocument();
$xml->preserveWhiteSpace = false;
$xml->formatOutput = true;
$xml->load(ASSETS . '/xml/devkit_navigation.xml');
$root = $xml->documentElement;
$list = new XMLElement('ul');
$list->setAttribute('id', 'navigation');
// Add edit link:
$item = new XMLElement('li');
$item->appendChild(Widget::Anchor(
__('Edit'),
SYMPHONY_URL . '/blueprints/pages/edit/' . $this->_pagedata['id'] . '/'
));
$list->appendChild($item);
// Translate navigation names:
if ($root->hasChildNodes()) {
foreach ($root->childNodes as $item) {
if ($item->tagName == 'item') {
$item->setAttribute('name', __($item->getAttribute('name')));
}
}
}
/**
* Allow navigation XML to be manipulated before it is rendered.
*
* @delegate ManipulateDevKitNavigation
* @param string $context
* '/frontend/'
* @param DOMDocument $xml
*/
Symphony::ExtensionManager()->notifyMembers(
'ManipulateDevKitNavigation',
'/frontend/',
array(
'xml' => $xml
)
);
if ($root->hasChildNodes()) {
foreach ($root->childNodes as $node) {
if ($node->getAttribute('active') === 'yes') {
$item = new XMLElement('li', $node->getAttribute('name'));
} else {
$item = new XMLElement('li');
$item->appendChild(Widget::Anchor(
$node->getAttribute('name'),
'?' . $node->getAttribute('handle') . $this->_query_string
));
}
$list->appendChild($item);
}
}
$wrapper->appendChild($list);
}
/**
* This function builds a Jump menu, which is what a Devkit uses as it's
* internal navigation. Items are added to the Jump menu using the
* buildJumpItem function
*
* @see buildJumpItem
* @param XMLElement $wrapper
* The parent XMLElement that the jump menu will be appended
* to. By default this is `<div id='jump'>`
*/
protected function buildJump(XMLElement $wrapper)
{
}
/**
*
* @param string $name
* The name of the jump
* @param string $link
* The link for this jump item
* @param boolean $active
* Whether this is the active link, if true, this will add an
* active class to the link built. By default this is false
* @throws InvalidArgumentException
* @return XMLElement
*/
protected function buildJumpItem($name, $link, $active = false)
{
$item = new XMLElement('li');
$anchor = Widget::Anchor($name, $link);
$anchor->setAttribute('class', 'inactive');
if ($active) {
$anchor->setAttribute('class', 'active');
}
$item->appendChild($anchor);
return $item;
}
/**
* The content of the Devkit, defaults to empty.
*
* @param XMLElement $wrapper
* The parent XMLElement that the content will be appended
* to. By default this is `<div id='content'>`
*/
protected function buildContent(XMLElement $wrapper)
{
}
/**
* The prepare function acts a pseudo constructor for the Devkit,
* setting some base variables with the given parameters
*
* @param XSLTPage $page
* An instance of the XSLTPage, usually FrontendPage
* @param array $pagedata
* An associative array of the details of the Page that is
* being 'Devkitted'. The majority of this information is from
* tbl_pages table.
* @param string $xml
* The XML of the page that the XSLT will be applied to, this includes
* any datasource results.
* @param array $param
* An array of the page parameters, including those provided by
* datasources.
* @param string $output
* The resulting Page after it has been transformed, as a string. This is
* similar to what you would see if you 'view-sourced' a page.
*/
public function prepare(XSLTPage $page, array $pagedata, $xml, array $param, $output)
{
$this->_page = $page;
$this->_pagedata = $pagedata;
$this->_xml = $xml;
$this->_param = $param;
$this->_output = $output;
if (is_null($this->_title)) {
$this->_title = __('Utility');
}
}
/**
* Called when page is generated, this function calls each of the other
* other functions in this page to build the Header, the Navigation,
* the Jump menu and finally the content. This function calls it's parent
* generate function
*
* @see toolkit.HTMLPage#generate()
* @throws InvalidArgumentException
* @return string
*/
public function build(array $context = [])
{
parent::build($context);
$this->buildIncludes();
$header = new XMLElement('div');
$header->setAttribute('id', 'header');
$jump = new XMLElement('div');
$jump->setAttribute('id', 'jump');
$content = new XMLElement('div');
$content->setAttribute('id', 'content');
$this->buildHeader($header);
$this->buildNavigation($header);
$this->buildJump($jump);
$header->appendChild($jump);
$this->Body->appendChild($header);
$this->buildContent($content);
$this->Body->appendChild($content);
return $this->generate();
}
}