dipl: align with ipl, first step

This commit is contained in:
Thomas Gelf 2018-05-05 00:18:45 +02:00
parent be0d41459f
commit 403df971a1
15 changed files with 246 additions and 159 deletions

View File

@ -27,6 +27,7 @@ class Attribute
* *
* @param $name * @param $name
* @param $value * @param $value
* @throws ProgrammingError
*/ */
public function __construct($name, $value = null) public function __construct($name, $value = null)
{ {
@ -37,6 +38,7 @@ class Attribute
* @param $name * @param $name
* @param $value * @param $value
* @return static * @return static
* @throws ProgrammingError
*/ */
public static function create($name, $value) public static function create($name, $value)
{ {
@ -158,6 +160,7 @@ class Attribute
/** /**
* @param $name * @param $name
* @return static * @return static
* @throws ProgrammingError
*/ */
public static function createEmpty($name) public static function createEmpty($name)
{ {
@ -182,9 +185,9 @@ class Attribute
{ {
// TODO: escape differently // TODO: escape differently
if (is_array($value)) { if (is_array($value)) {
return Util::escapeForHtml(implode(' ', $value)); return Html::escapeForHtml(implode(' ', $value));
} else { } else {
return Util::escapeForHtml((string) $value); return Html::escapeForHtml((string) $value);
} }
} }
} }

View File

@ -8,10 +8,10 @@ use Icinga\Exception\ProgrammingError;
class Attributes class Attributes
{ {
/** @var Attribute[] */ /** @var Attribute[] */
protected $attributes = array(); protected $attributes = [];
/** @var callable */ /** @var callable */
protected $callbacks = array(); protected $callbacks = [];
/** @var string */ /** @var string */
protected $prefix = ''; protected $prefix = '';
@ -19,6 +19,7 @@ class Attributes
/** /**
* Attributes constructor. * Attributes constructor.
* @param Attribute[] $attributes * @param Attribute[] $attributes
* @throws ProgrammingError
*/ */
public function __construct(array $attributes = null) public function __construct(array $attributes = null)
{ {
@ -40,6 +41,7 @@ class Attributes
/** /**
* @param Attribute[] $attributes * @param Attribute[] $attributes
* @return static * @return static
* @throws ProgrammingError
*/ */
public static function create(array $attributes = null) public static function create(array $attributes = null)
{ {
@ -66,7 +68,7 @@ class Attributes
} elseif ($attributes !== null) { } elseif ($attributes !== null) {
throw new IcingaException( throw new IcingaException(
'Attributes, Array or Null expected, got %s', 'Attributes, Array or Null expected, got %s',
Util::getPhpTypeName($attributes) Html::getPhpTypeName($attributes)
); );
} }
return $self; return $self;
@ -85,6 +87,7 @@ class Attributes
* @param Attribute|string $attribute * @param Attribute|string $attribute
* @param string|array $value * @param string|array $value
* @return $this * @return $this
* @throws ProgrammingError
*/ */
public function add($attribute, $value = null) public function add($attribute, $value = null)
{ {
@ -106,9 +109,10 @@ class Attributes
} }
/** /**
* @param Attribute|string|array $attribute * @param Attribute|array|string $attribute
* @param string|array $value * @param string|array $value
* @return $this * @return $this
* @throws ProgrammingError
*/ */
public function set($attribute, $value = null) public function set($attribute, $value = null)
{ {
@ -134,6 +138,7 @@ class Attributes
/** /**
* @param $name * @param $name
* @return Attribute * @return Attribute
* @throws ProgrammingError
*/ */
public function get($name) public function get($name)
{ {
@ -146,18 +151,28 @@ class Attributes
/** /**
* @param $name * @param $name
* @return bool * @return Attribute|false
*/ */
public function delete($name) public function remove($name)
{ {
if ($this->has($name)) { if ($this->has($name)) {
$attribute = $this->attributes[$name];
unset($this->attributes[$name]); unset($this->attributes[$name]);
return true;
return $attribute;
} else { } else {
return false; return false;
} }
} }
/**
* @deprecated
*/
public function delete($name)
{
return $this->remove($name);
}
/** /**
* @param $name * @param $name
* @return bool * @return bool
@ -202,17 +217,19 @@ class Attributes
* @return $this * @return $this
* @throws ProgrammingError * @throws ProgrammingError
*/ */
public function registerCallbackFor($name, $callback) public function registerAttributeCallback($name, $callback)
{ {
if (! is_callable($callback)) { if (! is_callable($callback)) {
throw new ProgrammingError('registerCallBack expects a callable callback'); throw new ProgrammingError(__METHOD__ . ' expects a callable callback');
} }
$this->callbacks[$name] = $callback; $this->callbacks[$name] = $callback;
return $this; return $this;
} }
/** /**
* @inheritdoc * @return string
* @throws ProgrammingError
*/ */
public function render() public function render()
{ {
@ -220,7 +237,7 @@ class Attributes
return ''; return '';
} }
$parts = array(); $parts = [];
foreach ($this->callbacks as $name => $callback) { foreach ($this->callbacks as $name => $callback) {
$attribute = call_user_func($callback); $attribute = call_user_func($callback);
if ($attribute instanceof Attribute) { if ($attribute instanceof Attribute) {

View File

@ -37,7 +37,7 @@ abstract class BaseElement extends Html
/** /**
* @return Attributes * @return Attributes
*/ */
public function attributes() public function getAttributes()
{ {
if ($this->attributes === null) { if ($this->attributes === null) {
$default = $this->getDefaultAttributes(); $default = $this->getDefaultAttributes();
@ -51,6 +51,14 @@ abstract class BaseElement extends Html
return $this->attributes; return $this->attributes;
} }
/**
* @deprecated
*/
public function attributes()
{
return $this->getAttributes();
}
/** /**
* @param Attributes|array|null $attributes * @param Attributes|array|null $attributes
* @return $this * @return $this
@ -61,13 +69,19 @@ abstract class BaseElement extends Html
return $this; return $this;
} }
public function setAttribute($key, $value)
{
$this->getAttributes()->set($key, $value);
return $this;
}
/** /**
* @param Attributes|array|null $attributes * @param Attributes|array|null $attributes
* @return $this * @return $this
*/ */
public function addAttributes($attributes) public function addAttributes($attributes)
{ {
$this->attributes()->add($attributes); $this->getAttributes()->add($attributes);
return $this; return $this;
} }
@ -93,6 +107,8 @@ abstract class BaseElement extends Html
* @param string $tag * @param string $tag
* @param Attributes|array $attributes * @param Attributes|array $attributes
* *
* @deprecated
*
* @return Element * @return Element
*/ */
public function addElement($tag, $attributes = null) public function addElement($tag, $attributes = null)
@ -155,7 +171,7 @@ abstract class BaseElement extends Html
if ($this->attributes === null && empty($this->defaultAttributes)) { if ($this->attributes === null && empty($this->defaultAttributes)) {
return ''; return '';
} else { } else {
return $this->attributes()->render(); return $this->getAttributes()->render();
} }
} }

View File

@ -55,7 +55,7 @@ class DeferredText implements ValidHtml
if ($this->escaped) { if ($this->escaped) {
return $callback(); return $callback();
} else { } else {
return Util::escapeForHtml($callback()); return Html::escapeForHtml($callback());
} }
} }
@ -80,7 +80,7 @@ class DeferredText implements ValidHtml
try { try {
return $this->render(); return $this->render();
} catch (Exception $e) { } catch (Exception $e) {
return Util::renderError($e); return Html::renderError($e);
} }
} }
} }

View File

@ -16,7 +16,7 @@ class Element extends BaseElement
$this->tag = $tag; $this->tag = $tag;
if ($attributes !== null) { if ($attributes !== null) {
$this->attributes = $this->attributes()->add($attributes); $this->attributes = $this->getAttributes()->add($attributes);
} }
if ($content !== null) { if ($content !== null) {

View File

@ -12,15 +12,26 @@ class FormattedString implements ValidHtml
/** @var ValidHtml */ /** @var ValidHtml */
protected $string; protected $string;
/**
* FormattedString constructor.
* @param $string
* @param array $arguments
* @throws \Icinga\Exception\IcingaException
*/
public function __construct($string, array $arguments = []) public function __construct($string, array $arguments = [])
{ {
$this->string = Util::wantHtml($string); $this->string = Html::wantHtml($string);
foreach ($arguments as $key => $val) { foreach ($arguments as $key => $val) {
$this->arguments[$key] = Util::wantHtml($val); $this->arguments[$key] = Html::wantHtml($val);
} }
} }
/**
* @param $string
* @return static
* @throws \Icinga\Exception\IcingaException
*/
public static function create($string) public static function create($string)
{ {
$args = func_get_args(); $args = func_get_args();

View File

@ -4,6 +4,7 @@ namespace dipl\Html;
use Countable; use Countable;
use Exception; use Exception;
use Icinga\Exception\IcingaException;
use Icinga\Exception\ProgrammingError; use Icinga\Exception\ProgrammingError;
/** /**
@ -12,6 +13,15 @@ use Icinga\Exception\ProgrammingError;
*/ */
class Html implements ValidHtml, Countable class Html implements ValidHtml, Countable
{ {
/** Charset to be used - we only support UTF-8 */
const CHARSET = 'UTF-8';
/** @var int The flags we use for htmlspecialchars depend on our PHP version */
protected static $htmlEscapeFlags;
/** @var bool */
protected static $showTraces = true;
protected $contentSeparator = ''; protected $contentSeparator = '';
/** @var ValidHtml[] */ /** @var ValidHtml[] */
@ -31,7 +41,7 @@ class Html implements ValidHtml, Countable
$this->addContent($c); $this->addContent($c);
} }
} else { } else {
$this->addIndexedContent(Util::wantHtml($content)); $this->addIndexedContent(Html::wantHtml($content));
} }
return $this; return $this;
@ -68,7 +78,7 @@ class Html implements ValidHtml, Countable
} }
} else { } else {
$pos = 0; $pos = 0;
$html = Util::wantHtml($content); $html = Html::wantHtml($content);
array_unshift($this->content, $html); array_unshift($this->content, $html);
$this->incrementIndexKeys(); $this->incrementIndexKeys();
$this->addObjectPosition($html, $pos); $this->addObjectPosition($html, $pos);
@ -103,6 +113,22 @@ class Html implements ValidHtml, Countable
); );
} }
/**
* 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 Html|array|string $content * @param Html|array|string $content
* @return $this * @return $this
@ -209,6 +235,51 @@ class Html implements ValidHtml, Countable
return $element; return $element;
} }
/**
* @param $any
* @return ValidHtml
* @throws IcingaException
*/
public static function wantHtml($any)
{
if ($any instanceof ValidHtml) {
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"',
Html::getPhpTypeName($any)
);
}
}
public static function canBeRenderedAsString($any)
{
return is_string($any) || is_int($any) || is_null($any) || is_float($any);
}
/**
* @param $any
* @return string
*/
public static function getPhpTypeName($any)
{
if (is_object($any)) {
return get_class($any);
} else {
return gettype($any);
}
}
/** /**
* @param $name * @param $name
* @param $arguments * @param $arguments
@ -230,7 +301,7 @@ class Html implements ValidHtml, Countable
} }
} }
if (! empty($arguments)) { if (!empty($arguments)) {
if (null === $content) { if (null === $content) {
$content = $arguments; $content = $arguments;
} else { } else {
@ -245,9 +316,51 @@ class Html implements ValidHtml, Countable
* @param Exception|string $error * @param Exception|string $error
* @return string * @return string
*/ */
protected function renderError($error) public static function renderError($error)
{ {
return Util::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?
}
$output = sprintf(
// TODO: translate? Be careful when doing so, it must be failsafe!
"<div class=\"exception\">\n<h1><i class=\"icon-bug\">"
. "</i>Oops, an error occurred!</h1>\n<pre>%s</pre>\n",
static::escapeForHtml($msg)
);
if (static::showTraces()) {
$output .= sprintf(
"<pre>%s</pre>\n",
static::escapeForHtml($error->getTraceAsString())
);
}
$output .= "</div>\n";
return $output;
}
/**
* @param null $show
* @return bool|null
*/
public static function showTraces($show = null)
{
if ($show !== null) {
self::$showTraces = $show;
}
return self::$showTraces;
} }
/** /**
@ -258,7 +371,7 @@ class Html implements ValidHtml, Countable
try { try {
return $this->render(); return $this->render();
} catch (Exception $e) { } catch (Exception $e) {
return $this->renderError($e); return static::renderError($e);
} }
} }
@ -302,4 +415,27 @@ class Html implements ValidHtml, Countable
} }
} }
} }
/**
* 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 &#013;
*
* @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;
}
} }

View File

@ -9,7 +9,7 @@ class Icon extends BaseElement
public function __construct($name, $attributes = null) public function __construct($name, $attributes = null)
{ {
$this->setAttributes($attributes); $this->setAttributes($attributes);
$this->attributes()->add('class', array('icon', 'icon-' . $name)); $this->getAttributes()->add('class', array('icon', 'icon-' . $name));
} }
/** /**

View File

@ -30,7 +30,7 @@ class Img extends BaseElement
/** @var Img $img */ /** @var Img $img */
$img = new static(); $img = new static();
$img->setAttributes($attributes); $img->setAttributes($attributes);
$img->attributes()->registerCallbackFor('src', array($img, 'getSrcAttribute')); $img->getAttributes()->registerAttributeCallback('src', array($img, 'getSrcAttribute'));
$img->setUrl($url, $urlParams); $img->setUrl($url, $urlParams);
return $img; return $img;
} }

View File

@ -23,7 +23,7 @@ class Link extends BaseElement
{ {
$this->setContent($content); $this->setContent($content);
$this->setAttributes($attributes); $this->setAttributes($attributes);
$this->attributes()->registerCallbackFor('href', array($this, 'getHrefAttribute')); $this->getAttributes()->registerAttributeCallback('href', array($this, 'getHrefAttribute'));
$this->setUrl($url, $urlParams); $this->setUrl($url, $urlParams);
} }

View File

@ -170,7 +170,7 @@ class Table extends BaseElement
{ {
$classes = $this->getRowClasses($row); $classes = $this->getRowClasses($row);
if (! empty($classes)) { if (! empty($classes)) {
$tr->attributes()->add('class', $classes); $tr->getAttributes()->add('class', $classes);
} }
return $tr; return $tr;

View File

@ -57,7 +57,7 @@ class Text implements ValidHtml
if ($this->escaped) { if ($this->escaped) {
return $this->string; return $this->string;
} else { } else {
return Util::escapeForHtml($this->string); return Html::escapeForHtml($this->string);
} }
} }
@ -70,7 +70,7 @@ class Text implements ValidHtml
*/ */
protected function renderError($error) protected function renderError($error)
{ {
return Util::renderError($error); return Html::renderError($error);
} }
/** /**

View File

@ -2,152 +2,56 @@
namespace dipl\Html; namespace dipl\Html;
use Exception; /**
use Icinga\Exception\IcingaException; * @deprecated
*/
class Util class Util
{ {
/** /**
* Charset to be used - we only support UTF-8 * @deprecated
*/
const CHARSET = 'UTF-8';
/**
* The flags we use for htmlspecialchars depend on our PHP version
*/
protected static $htmlEscapeFlags;
/** @var bool */
protected static $showTraces = true;
/**
* 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) public static function escapeForHtml($value)
{ {
return htmlspecialchars( return Html::escapeForHtml($value);
$value,
static::htmlEscapeFlags(),
self::CHARSET,
true
);
} }
/** /**
* @param Exception|string $error * @deprecated
* @return string
*/ */
public static function renderError($error) public static function renderError($error)
{ {
if ($error instanceof Exception) { return Html::renderError($error);
$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?
}
$output = sprintf(
// TODO: translate? Be careful when doing so, it must be failsafe!
"<div class=\"exception\">\n<h1><i class=\"icon-bug\">"
. "</i>Oops, an error occurred!</h1>\n<pre>%s</pre>\n",
static::escapeForHtml($msg)
);
if (static::showTraces()) {
$output .= sprintf(
"<pre>%s</pre>\n",
static::escapeForHtml($error->getTraceAsString())
);
}
$output .= "</div>\n";
return $output;
}
public static function showTraces($show = null)
{
if ($show !== null) {
self::$showTraces = $show;
}
return self::$showTraces;
} }
/** /**
* @param $any * @deprecated
* @return ValidHtml */
* @throws IcingaException public static function showTraces($show = null)
{
return Html::showTraces($show);
}
/**
* @deprecated
*/ */
public static function wantHtml($any) public static function wantHtml($any)
{ {
if ($any instanceof ValidHtml) { return Html::wantHtml($any);
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) || is_float($any);
} }
/** /**
* @param $any * @deprecated
* @return string */
public static function canBeRenderedAsString($any)
{
return Html::canBeRenderedAsString($any);
}
/**
* @deprecated
*/ */
public static function getPhpTypeName($any) public static function getPhpTypeName($any)
{ {
if (is_object($any)) { return Html::getPhpTypeName($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 &#013;
*
* @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;
} }
} }

View File

@ -156,11 +156,11 @@ trait ZfSortablePriority
); );
if ($this->isOnFirstRow()) { if ($this->isOnFirstRow()) {
$up->attributes()->add('disabled', 'disabled'); $up->getAttributes()->add('disabled', 'disabled');
} }
if ($this->isOnLastRow()) { if ($this->isOnLastRow()) {
$down->attributes()->add('disabled', 'disabled'); $down->getAttributes()->add('disabled', 'disabled');
} }
return [$down, $up]; return [$down, $up];

View File

@ -19,7 +19,7 @@ class ActionBar extends BaseElement
*/ */
public function setBaseTarget($target) public function setBaseTarget($target)
{ {
$this->attributes()->set('data-base-target', $target); $this->getAttributes()->set('data-base-target', $target);
return $this; return $this;
} }
} }