core/model/modx/moddashboardwidget.class.php
<?php
/*
* This file is part of MODX Revolution.
*
* Copyright (c) MODX, LLC. All Rights Reserved.
*
* For complete copyright and license information, see the COPYRIGHT and LICENSE
* files found in the top-level directory of this distribution.
*/
/**
* Abstraction of a Dashboard Widget, which can be placed on Dashboards for welcome screen customization.
*
* @property string $name The name of this widget
* @property string $description A short description, or lexicon key, of this widget
* @property string $type The type of widget that this is: file/snippet/html
* @property string $content The content, or location, of this widget
* @property string $namespace The namespace key of this widget
* @property string $lexicon The lexicon that will be loaded for this widget's description/execution
*
* @property modNamespace $Namespace The Namespace this widget is related to
* @property array $Placements An array of Placements this widget has been put on in Dashboards
* @package modx
*/
class modDashboardWidget extends xPDOSimpleObject {
public function toArray($keyPrefix = '',$rawValues = false,$excludeLazy = false,$includeRelated = false) {
$array = parent::toArray($keyPrefix,$rawValues,$excludeLazy);
if (!empty($this->xpdo->lexicon) && $this->xpdo->lexicon instanceof modLexicon) {
if ($this->get('lexicon') != 'core:dashboards') {
$this->xpdo->lexicon->load($this->get('lexicon'));
}
$array['name_trans'] = $this->xpdo->lexicon->exists($this->get('name')) ? $this->xpdo->lexicon($this->get('name')) : $this->get('name');
$array['description_trans'] = $this->xpdo->lexicon->exists($this->get('description')) ? $this->xpdo->lexicon($this->get('description')) : $this->get('description');
}
return $array;
}
/**
* Return the output for the widget, processed by type
*
* @param modManagerController $controller
* @return mixed
*/
public function getContent($controller) {
/** @var string $lexicon */
$lexicon = $this->get('lexicon');
if (!empty($lexicon) && !empty($this->xpdo->lexicon)) {
$this->xpdo->lexicon->load($lexicon);
}
/** @var modNamespace $namespace */
$namespace = $this->getOne('Namespace');
/** @var string $content */
$content = $this->get('content');
/** @var modDashboardWidgetInterface $widget */
$widget = null;
switch (strtolower($this->get('type'))) {
/* file/class-based widget */
case 'file':
$content = str_replace(array(
'[[++base_path]]',
'[[++core_path]]',
'[[++manager_path]]',
'[[++assets_path]]',
'[[++manager_theme]]',
),array(
$this->xpdo->getOption('base_path',null,MODX_BASE_PATH),
$this->xpdo->getOption('core_path',null,MODX_CORE_PATH),
$this->xpdo->getOption('manager_path',null,MODX_MANAGER_PATH),
$this->xpdo->getOption('assets_path',null,MODX_ASSETS_PATH),
$this->xpdo->getOption('manager_theme',null,'default'),
),$content);
if (file_exists($content)) {
$modx =& $this->xpdo;
$scriptProperties = $this->toArray();
ob_start();
$className = include_once $content;
$buffer = ob_get_contents();
ob_end_clean();
if (class_exists($className)) { /* is a class-based widget */
/** @var modDashboardWidgetInterface $widget */
$widget = new $className($this->xpdo,$this,$controller);
} else { /* just a standard file with a return */
if (($className === 1 || $className === true) && !empty($buffer)) {
$className = $buffer;
}
$widget = new modDashboardFileWidget($this->xpdo,$this,$controller);
$widget->setContent($className);
}
}
break;
/* Snippet widget */
case 'snippet':
$widget = new modDashboardSnippetWidget($this->xpdo,$this,$controller);
break;
/* PHP (Snippet) widget */
case 'php':
$widget = new modDashboardPhpWidget($this->xpdo,$this,$controller);
break;
/* HTML/static content widget */
case 'html':
default:
$widget = new modDashboardHtmlWidget($this->xpdo,$this,$controller);
break;
}
// Make sure we actually have a widget before proceeding
if ($widget === null) {
if ($controller === null) {
$this->xpdo->log(xPDO::LOG_LEVEL_ERROR, 'Failed to load dashboard widget with unknown controller.');
return null;
}
$this->xpdo->log(xPDO::LOG_LEVEL_ERROR, 'Failed to load dashboard widget with controller title "' . $controller->getPageTitle() . '".');
return null;
}
if (!empty($namespace)) {
$widget->setNamespace($namespace);
}
return $widget->process();
}
}
/**
* A file-based widget that returns only the content of its include.
*
* @package modx
* @subpackage dashboard
*/
class modDashboardFileWidget extends modDashboardWidgetInterface {
public function render() {
return $this->content;
}
}
/**
* A widget that contains only HTML.
*
* @package modx
* @subpackage dashboard
*/
class modDashboardHtmlWidget extends modDashboardWidgetInterface {
public function render() {
return $this->widget->get('content');
}
}
/**
* A widget that runs its content as PHP in Snippet-like format to get its content.
* @package modx
* @subpackage dashboard
*/
class modDashboardPhpWidget extends modDashboardWidgetInterface {
public function render() {
return $this->renderAsSnippet();
}
}
/**
* A Snippet-based widget that loads a MODX Snippet to return its content.
* @package modx
* @subpackage dashboard
*/
class modDashboardSnippetWidget extends modDashboardWidgetInterface {
public function render() {
/** @var modSnippet $snippet */
$snippet = $this->modx->getObject('modSnippet',array(
'name' => $this->widget->get('content'),
));
if ($snippet) {
$snippet->setCacheable(false);
$content = $snippet->process(array(
'controller' => $this->controller,
));
} else {
$content = '';
}
return $content;
}
}
/**
* Abstract class used for creating Dashboard Widgets. In your widget file, simply return the name of the class
* at the end of the file, and MODX will instantiate your class as a widget, and run the render() method to get
* the widget output.
*
* @abstract
* @package modx
* @subpackage dashboard
*/
abstract class modDashboardWidgetInterface {
/**
* A reference to the modX|xPDO instance
* @var xPDO|modX $modx
*/
public $modx;
/**
* A reference to the currently loaded manager controller
* @var modManagerController $controller
*/
public $controller;
/**
* A reference to this class's widget
* @var modDashboardWidget $widget
*/
public $widget;
/**
* A reference to the Namespace that this widget is executing in
* @var modNamespace $namespace
*/
public $namespace;
/**
* Allows widgets to specify a CSS class to attach to the block
*
* @var string
*/
public $cssBlockClass = '';
/**
* @var string
*/
public $content = '';
/**
* @param xPDO|modX $modx A reference to the modX instance
* @param modDashboardWidget $widget A reference to this class's widget
* @param modManagerController $controller A reference to the currently loaded manager controller
*/
function __construct(xPDO &$modx,modDashboardWidget &$widget,modManagerController &$controller) {
$this->modx =& $modx;
$this->widget =& $widget;
$this->controller =& $controller;
}
/**
* Set the widget content
* @param string $content
* @return void
*/
public function setContent($content) {
$this->content = $content;
}
/**
* Renders the content of the block in the appropriate size
* @return string
*/
public function process() {
$output = $this->render();
if (!empty($output)) {
$widgetArray = $this->widget->toArray();
$widgetArray['content'] = $output;
$widgetArray['class'] = $this->cssBlockClass;
$output = $this->getFileChunk('dashboard/block.tpl',$widgetArray);
$output = preg_replace('/\[\[([^\[\]]++|(?R))*?]]/s','',$output);
}
return $output;
}
/**
* Sets the Namespace that this widget will execute in
* @param modNamespace $namespace
* @return void
*/
public function setNamespace(modNamespace $namespace) {
$this->namespace =& $namespace;
}
/**
* Returns an array of placeholders for the block from the widget class. Override to add or change placeholders.
* @return array
*/
public function toArray() {
return $this->widget->toArray();
}
/**
* Must be declared in your derivative class. Must return the processed output of the widget.
* @abstract
* @return string
*/
abstract public function render();
/**
* @param string $tpl
* @param array $placeholders
* @return string
*/
public function getFileChunk($tpl,array $placeholders = array()) {
$output = '';
$file = $tpl;
if (!file_exists($file)) {
$file = $this->modx->getOption('manager_path').'templates/'.$this->modx->getOption('manager_theme',null,'default').'/'.$tpl;
}
if (!file_exists($file)) {
$file = $this->modx->getOption('manager_path').'templates/default/'.$tpl;
}
if (file_exists($file)) {
/** @var modChunk $chunk */
$chunk = $this->modx->newObject('modChunk');
$chunk->setCacheable(false);
$tplContent = file_get_contents($file);
$chunk->setContent($tplContent);
$output = $chunk->process($placeholders);
}
return $output;
}
/**
* Render the widget content as if it were a Snippet
*
* @param string $content
* @return string
*/
public function renderAsSnippet($content = '') {
if (empty($content)) $content = $this->widget->get('content');
$content = str_replace(array('<?php','?>'),'',$content);
$closure = function ($scriptProperties) use ($content) {
global $modx;
if (is_array($scriptProperties)) {
extract($scriptProperties, EXTR_SKIP);
}
return eval($content);
};
return $closure(array(
'controller' => $this->controller,
));
}
}