Web\Component: introduce a couple of web components

This commit is contained in:
Thomas Gelf 2016-11-22 15:00:09 +01:00
parent 6da0c7c722
commit 8151769592
6 changed files with 620 additions and 0 deletions

View file

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

View file

@ -0,0 +1,98 @@
<?php
namespace Icinga\Module\Businessprocess\Web\Component;
class Attribute extends Component
{
/** @var string */
protected $name;
/** @var string|array */
protected $value;
/**
* Attribute constructor.
*
* @param $name
* @param $value
*/
public function __construct($name, $value)
{
$this->name = $name;
$this->value = $value;
}
/**
* @param $name
* @param $value
* @return static
*/
public static function create($name, $value)
{
return new static($name, $value);
}
/**
* @return string
*/
public function getName()
{
return $this->name;
}
/**
* @return string
*/
public function getValue()
{
return $this->value;
}
/**
* @return string
*/
public function render()
{
return sprintf(
'%s="%s"',
$this->renderName(),
$this->renderValue()
);
}
/**
* @return string
*/
public function renderName()
{
return static::escapeName($this->name);
}
/**
* @return string
*/
public function renderValue()
{
return static::escapeValue($this->value);
}
/**
* @param $name
* @return string
*/
public static function escapeName($name)
{
// TODO: escape
return (string) $name;
}
/**
* @param $value
* @return string
*/
public static function escapeValue($value)
{
// TODO: escape
return (string) $value;
}
}

View file

@ -0,0 +1,158 @@
<?php
namespace Icinga\Module\Businessprocess\Web\Component;
use Icinga\Exception\IcingaException;
class Attributes extends Component
{
/**
* @var Attribute[]
*/
protected $attributes;
/**
* Attributes constructor.
* @param Attribute[] $attributes
*/
public function __construct(array $attributes = null)
{
$this->attributes = array();
if (empty($attributes)) {
return;
}
foreach ($attributes as $key => $value) {
if ($value instanceof Attribute) {
$this->addAttribute($value);
} elseif (is_string($key)) {
$this->add($key, $value);
} elseif (is_array($value) && count($value) === 2) {
$this->add(array_shift($value), array_shift($value));
}
}
}
/**
* @param Attribute[] $attributes
* @return static
*/
public static function create(array $attributes = null)
{
return new static($attributes);
}
/**
* @param Attributes|array|null $attributes
* @return static
*/
public static function wantAttributes($attributes)
{
if ($attributes instanceof Attributes) {
return $attributes;
} else {
$self = new static();
if (is_array($attributes)) {
foreach ($attributes as $k => $v) {
$self->add($k, $v);
}
return $self;
} elseif ($attributes !== null) {
throw new IcingaException(
'Attributes, Array or Null expected, got %s',
$self->getPhpTypeName($attributes)
);
}
return $self;
}
}
/**
* @return Attribute[]
*/
public function attributes()
{
return $this->attributes;
}
/**
* @param Attribute|string $attribute
* @param string|array $value
* @return $this
*/
public function add($attribute, $value = null)
{
if ($attribute instanceof static) {
foreach ($attribute as $a) {
$this->add($a);
}
return $this;
} elseif ($attribute instanceof Attribute) {
return $this->addAttribute($attribute);
} else {
return $this->addAttribute(Attribute::create($attribute, $value));
}
}
/**
* @param Attribute|string $attribute
* @param string|array $value
* @return $this
*/
public function set($attribute, $value = null)
{
if ($attribute instanceof static) {
foreach ($attribute as $a) {
$this->setAttribute($a);
}
return $this;
} else if ($attribute instanceof Attribute) {
return $this->setAttribute($attribute);
} else {
return $this->setAttribute(new Attribute($attribute, $value));
}
}
/**
* @param Attribute $attribute
* @return $this
*/
public function addAttribute(Attribute $attribute)
{
$name = $attribute->getName();
if (array_key_exists($name, $this->attributes)) {
$this->attributes[$name]->addValue($attribute->getValue());
} else {
$this->attributes[$name] = $attribute;
}
return $this;
}
/**
* @param Attribute $attribute
* @return $this
*/
public function setAttribute(Attribute $attribute)
{
$name = $attribute->getName();
$this->attributes[$name] = $attribute;
return $this;
}
/**
* @inheritdoc
*/
public function render()
{
if (empty($this->attributes)) {
return '';
}
return ' ' . implode(' ', $this->attributes);
}
}

View file

@ -0,0 +1,134 @@
<?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) {
$viewRenderer = Icinga::app()->getViewRenderer();
if ($viewRenderer->view === null) {
$viewRenderer->initView();
}
self::$discoveredView = $viewRenderer->view;
}
return self::$discoveredView;
}
/**
* @return string
*/
abstract 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

@ -0,0 +1,144 @@
<?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
);
}
}

View file

@ -0,0 +1,76 @@
<?php
namespace Icinga\Module\Businessprocess\Web\Component;
use Icinga\Web\Url;
class Link extends Component
{
/** @var string TODO: mixed, allow components */
protected $text;
/** @var Url */
protected $url;
/** @var Attributes */
protected $attributes;
protected function __construct()
{
}
/**
* @param Component|string $text
* @param Url|string $url
* @param array $urlParams
* @param array $attributes
*
* @return static
*/
public static function create($text, $url, $urlParams = null, array $attributes = null)
{
$link = new static();
$link->text = $text;
if ($url instanceof Url) {
if ($urlParams !== null) {
$url->addParams($urlParams);
}
$link->url = $url;
} else {
$link->url = Url::fromPath($url, $urlParams);
}
$link->attributes = new Attributes($attributes);
return $link;
}
/**
* @return string
*/
public function getRenderedText()
{
return $this->view()->escape((string) $this->text);
}
/**
* @return Url
*/
public function getUrl()
{
return $this->url;
}
/**
* @inheritdoc
*/
public function render()
{
return sprintf(
'<a href="%s"%s>%s</a>',
$this->getUrl(),
$this->attributes->render(),
$this->getRenderedText()
);
}
}