mirror of
https://github.com/Icinga/icingaweb2-module-businessprocess.git
synced 2026-01-11 15:42:53 -05:00
Html: a bunch of new classes, some changes
This commit is contained in:
parent
34ef3f26af
commit
ea7e79248c
11 changed files with 544 additions and 21 deletions
|
|
@ -1,6 +1,6 @@
|
|||
<?php
|
||||
|
||||
namespace Icinga\Module\Businessprocess\Web\Html;
|
||||
namespace Icinga\Module\Businessprocess\Html;
|
||||
|
||||
class Attribute
|
||||
{
|
||||
|
|
|
|||
|
|
@ -1,13 +1,13 @@
|
|||
<?php
|
||||
|
||||
namespace Icinga\Module\Businessprocess\Web\Html;
|
||||
namespace Icinga\Module\Businessprocess\Html;
|
||||
|
||||
use Icinga\Exception\IcingaException;
|
||||
use Icinga\Exception\ProgrammingError;
|
||||
|
||||
class Attributes
|
||||
{
|
||||
/** @var Attribute */
|
||||
/** @var Attribute[] */
|
||||
protected $attributes = array();
|
||||
|
||||
/** @var callable */
|
||||
|
|
@ -64,7 +64,7 @@ class Attributes
|
|||
} elseif ($attributes !== null) {
|
||||
throw new IcingaException(
|
||||
'Attributes, Array or Null expected, got %s',
|
||||
$self->getPhpTypeName($attributes)
|
||||
Util::getPhpTypeName($attributes)
|
||||
);
|
||||
}
|
||||
return $self;
|
||||
|
|
@ -74,7 +74,7 @@ class Attributes
|
|||
/**
|
||||
* @return Attribute[]
|
||||
*/
|
||||
public function attributes()
|
||||
public function getAttributes()
|
||||
{
|
||||
return $this->attributes;
|
||||
}
|
||||
|
|
@ -87,16 +87,20 @@ class Attributes
|
|||
public function add($attribute, $value = null)
|
||||
{
|
||||
if ($attribute instanceof static) {
|
||||
foreach ($attribute as $a) {
|
||||
foreach ($attribute->getAttributes() as $a) {
|
||||
$this->add($a);
|
||||
}
|
||||
|
||||
return $this;
|
||||
} elseif ($attribute instanceof Attribute) {
|
||||
return $this->addAttribute($attribute);
|
||||
$this->addAttribute($attribute);
|
||||
} elseif (is_array($attribute)) {
|
||||
foreach ($attribute as $name => $value) {
|
||||
$this->add($name, $value);
|
||||
}
|
||||
} else {
|
||||
return $this->addAttribute(Attribute::create($attribute, $value));
|
||||
$this->addAttribute(Attribute::create($attribute, $value));
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -151,6 +155,7 @@ class Attributes
|
|||
*
|
||||
* @param $name
|
||||
* @param $callback
|
||||
* @return $this
|
||||
*/
|
||||
public function registerCallbackFor($name, callable $callback)
|
||||
{
|
||||
|
|
|
|||
130
library/Businessprocess/Html/BaseElement.php
Normal file
130
library/Businessprocess/Html/BaseElement.php
Normal file
|
|
@ -0,0 +1,130 @@
|
|||
<?php
|
||||
|
||||
namespace Icinga\Module\Businessprocess\Html;
|
||||
|
||||
use Exception;
|
||||
|
||||
abstract class BaseElement extends Html
|
||||
{
|
||||
/** @var array You may want to set default attributes when extending this class */
|
||||
protected $defaultAttributes;
|
||||
|
||||
/** @var Attributes */
|
||||
protected $attributes;
|
||||
|
||||
/** @var string */
|
||||
protected $tag;
|
||||
|
||||
/**
|
||||
* @return Attributes
|
||||
*/
|
||||
public function attributes()
|
||||
{
|
||||
if ($this->attributes === null) {
|
||||
$default = $this->getDefaultAttributes();
|
||||
if (empty($default)) {
|
||||
$this->attributes = new Attributes();
|
||||
} else {
|
||||
$this->attributes = Attributes::wantAttributes($default);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return $this->attributes;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Attributes|array|null $attributes
|
||||
* @return $this
|
||||
*/
|
||||
public function setAttributes($attributes)
|
||||
{
|
||||
$this->attributes = Attributes::wantAttributes($attributes);
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Attributes|array|null $attributes
|
||||
* @return $this
|
||||
*/
|
||||
public function addAttributes($attributes)
|
||||
{
|
||||
$this->attributes = Attributes::wantAttributes($attributes);
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getDefaultAttributes()
|
||||
{
|
||||
return $this->defaultAttributes;
|
||||
}
|
||||
|
||||
public function setTag($tag)
|
||||
{
|
||||
$this->tag = $tag;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getTag()
|
||||
{
|
||||
return $this->tag;
|
||||
}
|
||||
|
||||
public function renderContent()
|
||||
{
|
||||
return parent::render();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function render()
|
||||
{
|
||||
$tag = $this->getTag();
|
||||
|
||||
return sprintf(
|
||||
'<%s%s>%s</%s>',
|
||||
$tag,
|
||||
$this->attributes()->render(),
|
||||
$this->renderContent(),
|
||||
$tag
|
||||
);
|
||||
}
|
||||
|
||||
protected function translate($msg)
|
||||
{
|
||||
// TODO: Not so nice
|
||||
return mt('businessprocess', $msg);
|
||||
}
|
||||
|
||||
/**
|
||||
* Whether the given something can be rendered
|
||||
*
|
||||
* @param mixed $any
|
||||
* @return bool
|
||||
*/
|
||||
protected function canBeRendered($any)
|
||||
{
|
||||
return is_string($any) || is_int($any) || is_null($any);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Exception|string $error
|
||||
* @return string
|
||||
*/
|
||||
protected function renderError($error)
|
||||
{
|
||||
return Util::renderError($error);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function __toString()
|
||||
{
|
||||
try {
|
||||
return $this->render();
|
||||
} catch (Exception $e) {
|
||||
return $this->renderError($e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,6 +1,6 @@
|
|||
<?php
|
||||
|
||||
namespace Icinga\Module\Businessprocess\Web\Html;
|
||||
namespace Icinga\Module\Businessprocess\Html;
|
||||
|
||||
class Container extends BaseElement
|
||||
{
|
||||
|
|
@ -10,6 +10,10 @@ class Container extends BaseElement
|
|||
/** @var string */
|
||||
protected $tag = 'div';
|
||||
|
||||
protected function __construct()
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Renderable|array|string $content
|
||||
* @param Attributes|array $attributes
|
||||
|
|
@ -17,10 +21,26 @@ class Container extends BaseElement
|
|||
*
|
||||
* @return static
|
||||
*/
|
||||
public static function create($content = array(), $attributes = null)
|
||||
public static function create($attributes = null, $content = null, $tag = null)
|
||||
{
|
||||
return new static($content, $attributes, $tag);
|
||||
$container = new static();
|
||||
if ($content !== null) {
|
||||
$container->setContent($content);
|
||||
}
|
||||
|
||||
if ($attributes !== null) {
|
||||
$container->setAttributes($attributes);
|
||||
}
|
||||
if ($tag !== null) {
|
||||
$container->setTag($tag);
|
||||
}
|
||||
|
||||
return $container;
|
||||
}
|
||||
}
|
||||
|
||||
class Old {
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
|
|
@ -64,4 +84,5 @@ class Container extends BaseElement
|
|||
$this->tag
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
34
library/Businessprocess/Html/Element.php
Normal file
34
library/Businessprocess/Html/Element.php
Normal file
|
|
@ -0,0 +1,34 @@
|
|||
<?php
|
||||
|
||||
namespace Icinga\Module\Businessprocess\Html;
|
||||
|
||||
class Element extends BaseElement
|
||||
{
|
||||
/**
|
||||
* Container constructor.
|
||||
*
|
||||
* @param string $tag
|
||||
* @param Attributes|array $attributes
|
||||
*/
|
||||
public function __construct($tag, $attributes = null)
|
||||
{
|
||||
$this->tag = $tag;
|
||||
|
||||
if ($attributes !== null) {
|
||||
$this->attributes = $this->attributes()->add($attributes);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Container constructor.
|
||||
*
|
||||
* @param string $tag
|
||||
* @param Attributes|array $attributes
|
||||
*
|
||||
* @return static
|
||||
*/
|
||||
public static function create($tag, $attributes = null)
|
||||
{
|
||||
return new static($tag, $attributes);
|
||||
}
|
||||
}
|
||||
120
library/Businessprocess/Html/Html.php
Normal file
120
library/Businessprocess/Html/Html.php
Normal file
|
|
@ -0,0 +1,120 @@
|
|||
<?php
|
||||
|
||||
namespace Icinga\Module\Businessprocess\Html;
|
||||
|
||||
use Icinga\Exception\ProgrammingError;
|
||||
|
||||
class Html implements Renderable
|
||||
{
|
||||
protected $contentSeparator = '';
|
||||
|
||||
/**
|
||||
* @var Renderable[]
|
||||
*/
|
||||
private $content = array();
|
||||
|
||||
public static function escape($any)
|
||||
{
|
||||
return Util::wantHtml($any);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Renderable $element
|
||||
* @return $this
|
||||
*/
|
||||
public function add(Renderable $element)
|
||||
{
|
||||
$this->content[] = $element;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Renderable|array|string $content
|
||||
* @return $this
|
||||
*/
|
||||
public function setContent($content)
|
||||
{
|
||||
$this->content = array(
|
||||
static::escape($content)
|
||||
);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Renderable|array|string $content
|
||||
* @return $this
|
||||
*/
|
||||
public function addContent($content)
|
||||
{
|
||||
$this->content[] = static::escape($content);
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* return Html
|
||||
*/
|
||||
public function getContent()
|
||||
{
|
||||
if ($this->content === null) {
|
||||
$this->content = array(new Html());
|
||||
}
|
||||
|
||||
return $this->content;
|
||||
}
|
||||
|
||||
public function hasContent()
|
||||
{
|
||||
if ($this->content === null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// TODO: unfinished
|
||||
// return $this->content->isEmpty();
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $separator
|
||||
* @return $this
|
||||
*/
|
||||
public function setSeparator($separator)
|
||||
{
|
||||
$this->contentSeparator = $separator;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
public function render()
|
||||
{
|
||||
$html = array();
|
||||
|
||||
foreach ($this->content as $element) {
|
||||
if (is_string($element)) {
|
||||
var_dump($this->content);
|
||||
}
|
||||
$html[] = $element->render();
|
||||
}
|
||||
|
||||
return implode($this->contentSeparator, $html);
|
||||
}
|
||||
|
||||
public static function element($name, $attributes = null)
|
||||
{
|
||||
// TODO: This might be anything here, add a better check
|
||||
if (! ctype_alnum($name)) {
|
||||
throw new ProgrammingError('Invalid element requested');
|
||||
}
|
||||
|
||||
$class = __NAMESPACE__ . '\\' . $name;
|
||||
/** @var Element $element */
|
||||
$element = new $class();
|
||||
if ($attributes !== null) {
|
||||
$element->setAttributes($attributes);
|
||||
}
|
||||
|
||||
return $element;
|
||||
}
|
||||
}
|
||||
8
library/Businessprocess/Html/HtmlString.php
Normal file
8
library/Businessprocess/Html/HtmlString.php
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
<?php
|
||||
|
||||
namespace Icinga\Module\Businessprocess\Html;
|
||||
|
||||
class HtmlString extends Text
|
||||
{
|
||||
protected $escaped = true;
|
||||
}
|
||||
|
|
@ -1,6 +1,6 @@
|
|||
<?php
|
||||
|
||||
namespace Icinga\Module\Businessprocess\Web\Html;
|
||||
namespace Icinga\Module\Businessprocess\Html;
|
||||
|
||||
use Icinga\Module\Businessprocess\Web\Url;
|
||||
use Icinga\Web\Url as WebUrl;
|
||||
|
|
@ -15,6 +15,10 @@ class Link extends BaseElement
|
|||
/** @var Url */
|
||||
protected $url;
|
||||
|
||||
protected function __construct()
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Renderable|array|string $content
|
||||
* @param Url|string $url
|
||||
|
|
@ -26,9 +30,10 @@ class Link extends BaseElement
|
|||
public static function create($content, $url, $urlParams = null, array $attributes = null)
|
||||
{
|
||||
$link = new static();
|
||||
$link->content = Util::wantHtml($content);
|
||||
$link->attributes()->registerCallbackFor('href', array($link, 'getHrefAttribute'));
|
||||
$link->setContent($content);
|
||||
$link->setAttributes($attributes);
|
||||
$link->attributes()->registerCallbackFor('href', array($link, 'getHrefAttribute'));
|
||||
$link->setUrl($url, $urlParams);
|
||||
return $link;
|
||||
}
|
||||
|
||||
|
|
@ -39,15 +44,16 @@ class Link extends BaseElement
|
|||
$url->addParams($urlParams);
|
||||
}
|
||||
|
||||
$link->url = $url;
|
||||
$this->url = $url;
|
||||
} else {
|
||||
if ($urlParams === null) {
|
||||
$link->url = Url::fromPath($url);
|
||||
$this->url = Url::fromPath($url);
|
||||
} else {
|
||||
$link->url = Url::fromPath($url, $urlParams);
|
||||
$this->url = Url::fromPath($url, $urlParams);
|
||||
}
|
||||
}
|
||||
$link->url->getParams();
|
||||
|
||||
$this->url->getParams();
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
8
library/Businessprocess/Html/Renderable.php
Normal file
8
library/Businessprocess/Html/Renderable.php
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
<?php
|
||||
|
||||
namespace Icinga\Module\Businessprocess\Html;
|
||||
|
||||
interface Renderable
|
||||
{
|
||||
public function render();
|
||||
}
|
||||
61
library/Businessprocess/Html/Text.php
Normal file
61
library/Businessprocess/Html/Text.php
Normal file
|
|
@ -0,0 +1,61 @@
|
|||
<?php
|
||||
|
||||
namespace Icinga\Module\Businessprocess\Html;
|
||||
|
||||
class Text implements Renderable
|
||||
{
|
||||
/** @var string */
|
||||
protected $string;
|
||||
|
||||
protected $escaped = false;
|
||||
|
||||
/**
|
||||
* Text constructor.
|
||||
*
|
||||
* @param $text
|
||||
*/
|
||||
public function __construct($string)
|
||||
{
|
||||
$this->string = (string) $string;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getText()
|
||||
{
|
||||
return $this->string;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param bool $escaped
|
||||
* @return $this
|
||||
*/
|
||||
public function setEscaped($escaped = true)
|
||||
{
|
||||
$this->escaped = $escaped;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $text
|
||||
*
|
||||
* @return static
|
||||
*/
|
||||
public static function create($text)
|
||||
{
|
||||
return new static($text);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function render()
|
||||
{
|
||||
if ($this->escaped) {
|
||||
return $this->string;
|
||||
} else {
|
||||
return Util::escapeForHtml($this->string);
|
||||
}
|
||||
}
|
||||
}
|
||||
130
library/Businessprocess/Html/Util.php
Normal file
130
library/Businessprocess/Html/Util.php
Normal file
|
|
@ -0,0 +1,130 @@
|
|||
<?php
|
||||
|
||||
namespace Icinga\Module\Businessprocess\Html;
|
||||
|
||||
use Exception;
|
||||
use Icinga\Exception\IcingaException;
|
||||
|
||||
class Util
|
||||
{
|
||||
/**
|
||||
* Charset to be used - we only support UTF-8
|
||||
*/
|
||||
const CHARSET = 'UTF-8';
|
||||
|
||||
/**
|
||||
* The flags we use for htmlspecialchars depend on our PHP version
|
||||
*/
|
||||
protected static $htmlEscapeFlags;
|
||||
|
||||
/**
|
||||
* Escape the given value top be safely used in view scripts
|
||||
*
|
||||
* @param string $value The output to be escaped
|
||||
* @return string
|
||||
*/
|
||||
public static function escapeForHtml($value)
|
||||
{
|
||||
return htmlspecialchars(
|
||||
$value,
|
||||
static::htmlEscapeFlags(),
|
||||
self::CHARSET,
|
||||
true
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Exception|string $error
|
||||
* @return string
|
||||
*/
|
||||
public static function renderError($error)
|
||||
{
|
||||
if ($error instanceof Exception) {
|
||||
$file = preg_split('/[\/\\\]/', $error->getFile(), -1, PREG_SPLIT_NO_EMPTY);
|
||||
$file = array_pop($file);
|
||||
$msg = sprintf(
|
||||
'%s (%s:%d)',
|
||||
$error->getMessage(),
|
||||
$file,
|
||||
$error->getLine()
|
||||
);
|
||||
} elseif (is_string($error)) {
|
||||
$msg = $error;
|
||||
} else {
|
||||
$msg = 'Got an invalid error'; // TODO: translate?
|
||||
}
|
||||
|
||||
return sprintf(
|
||||
'ERROR: %s', // TODO: translate?
|
||||
static::escapeForHtml($msg)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $any
|
||||
* @return Renderable
|
||||
* @throws IcingaException
|
||||
*/
|
||||
public static function wantHtml($any)
|
||||
{
|
||||
if ($any instanceof Renderable) {
|
||||
return $any;
|
||||
} elseif (static::canBeRenderedAsString($any)) {
|
||||
return new Text($any);
|
||||
} elseif (is_array($any)) {
|
||||
$html = new Html();
|
||||
foreach ($any as $el) {
|
||||
$html->add(static::wantHtml($el));
|
||||
}
|
||||
|
||||
return $html;
|
||||
} else {
|
||||
// TODO: Should we add a dedicated Exception class?
|
||||
throw new IcingaException(
|
||||
'String, Html Element or Array of such expected, got "%s"',
|
||||
Util::getPhpTypeName($any)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
public static function canBeRenderedAsString($any)
|
||||
{
|
||||
return is_string($any) || is_int($any) || is_null($any);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $any
|
||||
* @return string
|
||||
*/
|
||||
public static function getPhpTypeName($any)
|
||||
{
|
||||
if (is_object($any)) {
|
||||
return get_class($any);
|
||||
} else {
|
||||
return gettype($any);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This defines the flags used when escaping for HTML
|
||||
*
|
||||
* - Single quotes are not escaped (ENT_COMPAT)
|
||||
* - With PHP >= 5.4, invalid characters are replaced with <EFBFBD> (ENT_SUBSTITUTE)
|
||||
* - With PHP 5.3 they are ignored (ENT_IGNORE, less secure)
|
||||
* - Uses HTML5 entities for PHP >= 5.4, disallowing 
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
protected static function htmlEscapeFlags()
|
||||
{
|
||||
if (self::$htmlEscapeFlags === null) {
|
||||
if (version_compare(PHP_VERSION, '5.4.0') >= 0) {
|
||||
self::$htmlEscapeFlags = ENT_COMPAT | ENT_SUBSTITUTE | ENT_HTML5;
|
||||
} else {
|
||||
self::$htmlEscapeFlags = ENT_COMPAT | ENT_IGNORE;
|
||||
}
|
||||
}
|
||||
|
||||
return self::$htmlEscapeFlags;
|
||||
}
|
||||
}
|
||||
Loading…
Reference in a new issue