Html: introduce a new namespace

This commit is contained in:
Thomas Gelf 2016-11-27 23:54:03 +01:00
parent a00fdab37f
commit 34ef3f26af
7 changed files with 166 additions and 333 deletions

View file

@ -1,8 +1,8 @@
<?php
namespace Icinga\Module\Businessprocess\Web\Component;
namespace Icinga\Module\Businessprocess\Web\Html;
class Attribute extends Component
class Attribute
{
/** @var string */
protected $name;
@ -48,6 +48,34 @@ class Attribute extends Component
return $this->value;
}
/**
* @param string|array $value
* @return $this
*/
public function setValue($value)
{
$this->value = $value;
return $this;
}
/**
* @param string $value
* @return $this
*/
public function addValue($value)
{
if (! is_array($this->value)) {
$this->value = array($this->value);
}
if (is_array($value)) {
$this->value = array_merge($this->value, $value);
} else {
$this->value[] = $value;
}
return $this;
}
/**
* @return string
*/
@ -92,7 +120,11 @@ class Attribute extends Component
*/
public static function escapeValue($value)
{
// TODO: escape
return (string) $value;
// TODO: escape differently
if (is_array($value)) {
return Util::escapeForHtml(implode(' ', $value));
} else {
return Util::escapeForHtml((string) $value);
}
}
}

View file

@ -1,15 +1,17 @@
<?php
namespace Icinga\Module\Businessprocess\Web\Component;
namespace Icinga\Module\Businessprocess\Web\Html;
use Icinga\Exception\IcingaException;
use Icinga\Exception\ProgrammingError;
class Attributes extends Component
class Attributes
{
/**
* @var Attribute[]
*/
protected $attributes;
/** @var Attribute */
protected $attributes = array();
/** @var callable */
protected $callbacks = array();
/**
* Attributes constructor.
@ -17,7 +19,6 @@ class Attributes extends Component
*/
public function __construct(array $attributes = null)
{
$this->attributes = array();
if (empty($attributes)) {
return;
}
@ -44,7 +45,8 @@ class Attributes extends Component
/**
* @param Attributes|array|null $attributes
* @return static
* @return Attributes
* @throws IcingaException
*/
public static function wantAttributes($attributes)
{
@ -144,15 +146,42 @@ class Attributes extends Component
return $this;
}
/**
* Callback must return an instance of Attribute
*
* @param $name
* @param $callback
*/
public function registerCallbackFor($name, callable $callback)
{
$this->callbacks[$name] = $callback;
return $this;
}
/**
* @inheritdoc
*/
public function render()
{
if (empty($this->attributes)) {
if (empty($this->attributes) && empty($this->callbacks)) {
return '';
}
return ' ' . implode(' ', $this->attributes);
$parts = array();
foreach ($this->callbacks as $callback) {
$attribute = call_user_func($callback);
if (! $attribute instanceof Attribute) {
throw new ProgrammingError(
'A registered attribute callback must return an Attribute'
);
}
$parts[] = $attribute->render();
}
foreach ($this->attributes as $attribute) {
$parts[] = $attribute->render();
}
return ' ' . implode(' ', $parts);
}
}

View file

@ -0,0 +1,67 @@
<?php
namespace Icinga\Module\Businessprocess\Web\Html;
class Container extends BaseElement
{
/** @var string */
protected $contentSeparator = "\n";
/** @var string */
protected $tag = 'div';
/**
* @param Renderable|array|string $content
* @param Attributes|array $attributes
* @param string $tag
*
* @return static
*/
public static function create($content = array(), $attributes = null)
{
return new static($content, $attributes, $tag);
}
/**
* @inheritdoc
*/
public function render()
{
return $this->renderContainerFor(parent::render());
}
/**
* @inheritdoc
*/
public function renderError($error)
{
// TODO: eventually add class="error"
return $this->renderContainerFor(
parent::renderError($error)
);
}
/**
* @param bool $render
* @return $this
*/
public function renderIfEmpty($render = true)
{
$this->renderIfEmpty = $render;
return $this;
}
/**
* @param string $content
* @return string
*/
protected function renderContainerFor($content)
{
return sprintf(
'<%s%s>%s</%s>',
$this->tag,
$this->attributes->render(),
$content,
$this->tag
);
}
}

View file

@ -1,37 +1,39 @@
<?php
namespace Icinga\Module\Businessprocess\Web\Component;
namespace Icinga\Module\Businessprocess\Web\Html;
use Icinga\Module\Businessprocess\Web\Url;
use Icinga\Web\Url as WebUrl;
class Link extends Component
class Link extends BaseElement
{
/** @var string TODO: mixed, allow components */
protected $text;
protected $tag = 'a';
/** @var Renderable */
protected $content;
/** @var Url */
protected $url;
/** @var Attributes */
protected $attributes;
protected function __construct()
{
}
/**
* @param Component|string $text
* @param Renderable|array|string $content
* @param Url|string $url
* @param array $urlParams
* @param array $attributes
*
* @return static
*/
public static function create($text, $url, $urlParams = null, array $attributes = null)
public static function create($content, $url, $urlParams = null, array $attributes = null)
{
$link = new static();
$link->text = $text;
$link->content = Util::wantHtml($content);
$link->attributes()->registerCallbackFor('href', array($link, 'getHrefAttribute'));
$link->setAttributes($attributes);
return $link;
}
public function setUrl($url, $urlParams)
{
if ($url instanceof WebUrl) { // Hint: Url is also a WebUrl
if ($urlParams !== null) {
$url->addParams($urlParams);
@ -45,17 +47,15 @@ class Link extends Component
$link->url = Url::fromPath($url, $urlParams);
}
}
$link->attributes = new Attributes($attributes);
return $link;
$link->url->getParams();
}
/**
* @return string
* @return Attribute
*/
public function getRenderedText()
public function getHrefAttribute()
{
return $this->view()->escape((string) $this->text);
return new Attribute('href', $this->getUrl()->getAbsoluteUrl('&'));
}
/**
@ -63,19 +63,7 @@ class Link extends Component
*/
public function getUrl()
{
// TODO: What if null? #?
return $this->url;
}
/**
* @inheritdoc
*/
public function render()
{
return sprintf(
'<a href="%s"%s>%s</a>',
$this->getUrl(),
$this->attributes->render(),
$this->getRenderedText()
);
}
}

View file

@ -1,10 +1,10 @@
<?php
namespace Icinga\Module\Businessprocess\Web\Component;
namespace Icinga\Module\Businessprocess\Html;
class ActionBar extends Container
{
protected $separator = ' ';
protected $contentSeparator = ' ';
protected $attributes = array('class' => 'action-bar');
protected $defaultAttributes = array('class' => 'action-bar');
}

View file

@ -1,139 +0,0 @@
<?php
namespace Icinga\Module\Businessprocess\Web\Component;
use Exception;
use Icinga\Application\Icinga;
use Icinga\Exception\IcingaException;
use Icinga\Web\View;
abstract class Component
{
/** @var View */
private $view;
/** @var View */
private static $discoveredView;
/**
* @param View $view
* @return $this
*/
public function setView(View $view)
{
$this->view = $view;
return $this;
}
/**
* @return View
*/
public function view()
{
if ($this->view === null) {
$this->view = $this->discoveredView();
}
return $this->view;
}
/**
* @return View
*/
protected function discoveredView()
{
if (self::$discoveredView === null) {
$icinga = Icinga::app();
if ($icinga->isCli()) {
self::$discoveredView = new View();
} else {
$viewRenderer = $icinga->getViewRenderer();
if ($viewRenderer->view === null) {
$viewRenderer->initView();
}
self::$discoveredView = $viewRenderer->view;
}
}
return self::$discoveredView;
}
/**
* @return string
*/
abstract public function render();
public function wantHtml($any, $separator = '')
{
if ($any instanceof Component) {
return $any;
} elseif (is_string($any)) {
return $this->view()->escape($any);
} elseif (is_array($any)) {
$safe = array();
foreach ($any as $el) {
$safe .= $this->wantHtml($el);
}
return implode($separator, $safe);
} else {
// TODO: Should we add a dedicated Exception class?
throw new IcingaException(
'String, Web Component or Array of such expected, got "%s"',
$this->getPhpTypeName($any)
);
}
}
public function getPhpTypeName($any)
{
if (is_object($any)) {
return get_class($any);
} else {
return gettype($any);
}
}
/**
* @param Exception|string $error
* @return string
*/
protected 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';
}
$view = $this->view();
return sprintf(
$view->translate('ERROR: %s'),
$view->escape($msg)
);
}
/**
* @return string
*/
public function __toString()
{
try {
return $this->render();
} catch (Exception $e) {
return $this->renderError($e);
}
}
}

View file

@ -1,144 +0,0 @@
<?php
namespace Icinga\Module\Businessprocess\Web\Component;
class Container extends Component
{
/**
* @var array
*/
protected $content = array();
/** @var Attributes|array Is never an array at runtime, but may be before __construction */
protected $attributes;
/** @var string */
protected $separator = "\n";
/** @var string */
protected $tag = 'div';
/**
* Container constructor.
* @param Component|array|string $content
* @param Attributes|array $attributes
* @param string $tag
*/
protected function __construct($content = array(), $attributes = null, $tag = null)
{
$this->addContent($content);
if ($this->attributes === null) {
$this->attributes = Attributes::wantAttributes($attributes);
} else {
$this->attributes = Attributes::wantAttributes($this->attributes);
}
if ($tag !== null) {
$this->tag = $tag;
}
}
/**
* @param Component|array|string $content
* @param Attributes|array $attributes
* @param string $tag
*
* @return static
*/
public static function create($content = array(), $attributes = null, $tag = null)
{
return new static($content, $attributes, $tag);
}
/**
* @return Attributes
*/
public function attributes()
{
return $this->attributes;
}
/**
* @see addContent()
* @param Component|array|string $content
* @return $this
*/
public function add($content)
{
return $this->addContent($content);
}
/**
* @param Component|array|string $content
* @return $this
*/
public function addContent($content)
{
if (is_array($content)) {
foreach ($content as $c) {
$this->addContent($c);
}
}
$htmlOrComponent = $this->wantHtml($content);
if (strlen($htmlOrComponent)) {
$this->content[] = $htmlOrComponent;
}
return $this;
}
/**
* @param Component|array|string $content
* @return $this
*/
public function setContent($content)
{
$this->content = array();
$this->addContent($content);
return $this;
}
/**
* @return string
*/
public function renderContent()
{
return implode($this->separator, $this->content);
}
/**
* @inheritdoc
*/
public function render()
{
return $this->renderContainerFor($this->renderContent());
}
/**
* @inheritdoc
*/
public function renderError($error)
{
// TODO: eventually add class="error"
return $this->renderContainerFor(
parent::renderError($error)
);
}
/**
* @param $content
* @return string
*/
protected function renderContainerFor($content)
{
return sprintf(
'<%s%s>%s</%s>',
$this->tag,
$this->attributes->render(),
$content,
$this->tag
);
}
}