Initial xentral_oss_20.3.c9ffacf

This commit is contained in:
Alex
2021-05-21 08:49:41 +02:00
parent 5406e4a551
commit 34e5ac43d9
18884 changed files with 2109867 additions and 0 deletions
+443
View File
@@ -0,0 +1,443 @@
<?php
namespace Xentral\Widgets\DataTable\Column;
use JsonSerializable;
use Xentral\Widgets\DataTable\Exception\InvalidArgumentException;
use Xentral\Widgets\DataTable\Feature\ResponsiveFeature;
final class Column implements JsonSerializable
{
/** @var string ALIGN_LEFT */
const ALIGN_LEFT = 'left';
/** @var string ALIGN_RIGHT */
const ALIGN_RIGHT = 'right';
/** @var string ALIGN_CENTER */
const ALIGN_CENTER = 'center';
/** @var string ALIGN_JUSTIFY */
const ALIGN_JUSTIFY = 'justify';
/** @var array $validAlignments */
public static $validAlignments = [
self::ALIGN_LEFT,
self::ALIGN_RIGHT,
self::ALIGN_CENTER,
self::ALIGN_JUSTIFY,
];
/** @var string $name */
private $name;
/** @var string $title */
private $title;
/** @var bool $visible */
private $visible;
/** @var bool $sortable */
private $sortable;
/** @var bool $searchable */
private $searchable;
/** @var bool $exportable */
private $exportable;
/** @var bool $fixed */
private $fixed;
/** @var string $alignment */
private $alignment;
/** @var string|null $dbColumn */
private $dbColumn;
/** @var string|null $width */
private $width;
/** @var callable|null $formatter */
private $formatter;
/** @var array $properties */
private $properties = [];
/** @var array $cssClasses CSS classes */
private $cssClasses = [];
/**
* @param string $name
* @param string $title
* @param string $align [left|right|center|justify]
* @param string|null $width Column width as CSS value (e.g 20%, 3em, 55px)
* @param bool $visible Is column currently visible? Visibility can be changed at runtime
* @param bool $sortable
* @param bool $searchable
* @param bool $exportable
* @param bool $fixed If true, column is always visible and visibility can not be changed at runtime
* * Fixed columns can't be hidden (ResponsiveFeature, ColumnVisibilityFeature)
* * Fixed columns can't be reordered (ColumnReorderFeature)
*
* @throws InvalidArgumentException
*/
public function __construct(
$name,
$title,
$align = 'left',
$width = null,
$visible = true,
$sortable = false,
$searchable = false,
$exportable = false,
$fixed = false
) {
if (empty($name)) {
throw new InvalidArgumentException('Column name can not be empty.');
}
$cleanedName = (string)preg_replace('#[^a-z0-9_]#', '', trim($name));
if ($cleanedName !== $name) {
throw new InvalidArgumentException(sprintf(
'Name "%s" contains illegal characters. Valid characters are: a-z, 0-9 and underscore.',
$name
));
}
$this->name = (string)$name;
$this->title = (string)$title;
$this->visible = (bool)$visible;
$this->sortable = (bool)$sortable;
$this->searchable = (bool)$searchable;
$this->exportable = (bool)$exportable;
$this->fixed = (bool)$fixed;
$this->alignment = (string)$align;
$this->width = $width !== null ? (string)$width : null;
}
/**
* Currently hidden column; can be unhidden
*
* @param string $name
* @param string $title
* @param string $align [left|right|center|justify]
* @param string|null $width Column width as CSS value (e.g 20%, 3em, 55px)
*
* @return Column
*/
public static function hidden($name, $title, $align = 'left', $width = null)
{
return new static($name, $title, $align, $width, false, false, false, false, false);
}
/**
* Visible column; not sortable and not searchable
*
* @param string $name
* @param string $title
* @param string $align [left|right|center|justify]
* @param string|null $width Column width as CSS value (e.g 20%, 3em, 55px)
*
* @return Column
*/
public static function visible($name, $title, $align = 'left', $width = null)
{
return new static($name, $title, $align, $width, true, false, false, true, false);
}
/**
* Visible and sortable column; not searchable
*
* @param string $name
* @param string $title
* @param string $align [left|right|center|justify]
* @param string|null $width Column width as CSS value (e.g 20%, 3em, 55px)
*
* @return Column
*/
public static function sortable($name, $title, $align = 'left', $width = null)
{
return new static($name, $title, $align, $width, true, true, false, true, false);
}
/**
* Visible, sortable und searchable column
*
* @param string $name
* @param string $title
* @param string $align [left|right|center|justify]
* @param string|null $width Column width as CSS value (e.g 20%, 3em, 55px)
*
* @return Column
*/
public static function searchable($name, $title, $align = 'left', $width = null)
{
return new static($name, $title, $align, $width, true, true, true, true, false);
}
/**
* Always visible and with fixed position (for Menu and Selection columns)
*
* - Always visible; Can't be hidden (ColumnVisibilityFeature)
* - Fixed position; Can't be reordered (ColumnReorderFeature)
* - Not searchable
* - Not sortable
*
* @param string $name
* @param string $title
*
* @return Column
*/
public static function fixed($name, $title = '', $align = 'center', $width = null)
{
$fixed = new static($name, $title, $align, $width, true, false, false, false, true);
$fixed->set('responsivePriority', ResponsiveFeature::PRIO_HIGHER);
return $fixed;
}
/**
* @return string
*/
public function getName()
{
return $this->name;
}
/**
* @return string
*/
public function getTitle()
{
return $this->title;
}
/**
* @param string $dbColumn
*/
public function setDbColumn($dbColumn)
{
$this->dbColumn = (string)$dbColumn;
}
/**
* @return string|null
*/
public function getDbColumn()
{
return $this->dbColumn;
}
/**
* @return string
*/
public function getAlignment()
{
return $this->alignment;
}
/**
* @see $validAlignments
*
* @param string $alignment [left|right|center|justify]
*/
public function setAlignment($alignment)
{
if (!in_array($alignment, self::$validAlignments, true)) {
throw new InvalidArgumentException(sprintf(
'Alignment "%s" is not valid. Valid alignments: %s',
$alignment,
implode(', ', self::$validAlignments)
));
}
$this->alignment = $alignment;
}
/**
* @return callable|null
*/
public function getFormatter()
{
return $this->formatter;
}
/**
* @param callable $formatter
*
* @return void
*/
public function setFormatter(callable $formatter)
{
$this->formatter = $formatter;
}
/**
* @return bool
*/
public function isFixed()
{
return $this->fixed;
}
/**
* @return bool
*/
public function isVisible()
{
return $this->visible;
}
/**
* @return bool
*/
public function isSortable()
{
return $this->sortable;
}
/**
* @return bool
*/
public function isExportable()
{
return $this->exportable;
}
/**
* @return bool
*/
public function isSearchable()
{
return $this->searchable;
}
/**
* @param string $property
*
* @return bool
*/
public function has($property)
{
if (isset($this->{$property})) {
return true;
}
return isset($this->properties[$property]);
}
/**
* @param string $property
*
* @return mixed|null
*/
public function get($property)
{
if (isset($this->{$property})) {
return $this->{$property};
}
if (isset($this->properties[$property])) {
return $this->properties[$property];
}
return null;
}
/**
* @param string $property
* @param mixed $value
*
* @return void
*/
public function set($property, $value)
{
if (isset($this->{$property})) {
$this->{$property} = $value;
}
$this->properties[$property] = $value;
}
/**
* @param string $className
*
* @return bool
*/
public function hasCssClass($className)
{
return in_array($className, $this->cssClasses, true);
}
/**
* @param string $className
*
* @return void
*/
public function addCssClass($className)
{
$this->cssClasses[] = trim($className);
$this->cssClasses = array_unique($this->cssClasses);
}
/**
* @param string $className
*
* @return void
*/
public function removeCssClass($className)
{
$classKey = array_search($className, $this->cssClasses, true);
if ($classKey !== false) {
unset($this->cssClasses[$classKey]);
$this->cssClasses = array_values($this->cssClasses);
}
}
/**
* @return array
*/
public function toArray()
{
$result = $this->properties;
$result['data'] = isset($result['data']) ? $result['data'] : $this->name;
$result['name'] = $this->name;
$result['title'] = $this->title;
$result['exportable'] = $this->exportable;
$result['searchable'] = $this->searchable;
$result['orderable'] = $this->sortable;
$result['visible'] = $this->visible;
$result['fixed'] = $this->fixed;
if ($this->fixed === true) {
$result['visible'] = true;
}
// Spalte hat keine Daten; z.B. Menü-Spalte
if ($this->dbColumn === null) {
//$result['data'] = null;
$result['defaultContent'] = isset($result['defaultContent']) ? $result['defaultContent'] : '';
$result['orderable'] = false;
$result['searchable'] = false;
// $result['data'] = $this->name;
// $result['searchable'] = $this->searchable;
}
$cssClasses = $this->cssClasses;
$cssClasses[] = 'dt-' . $this->alignment;
$result['className'] = implode(' ', $cssClasses);
if ($this->width !== null) {
$result['width'] = $this->width;
}
return $result;
}
/**
* @return array
*/
public function jsonSerialize()
{
return $this->toArray();
}
}
@@ -0,0 +1,248 @@
<?php
namespace Xentral\Widgets\DataTable\Column;
use ArrayIterator;
use IteratorAggregate;
use JsonSerializable;
use Traversable;
use Xentral\Widgets\DataTable\Exception\ColumnNameAssignedException;
use Xentral\Widgets\DataTable\Exception\InvalidArgumentException;
class ColumnCollection implements JsonSerializable, IteratorAggregate
{
/** @var array|Column[] $columns */
protected $columns = [];
/**
* @param array|Column[] $columns
*/
public function __construct(array $columns = [])
{
foreach ($columns as $column) {
$this->add($column);
}
}
/**
* @param string $columnName
*
* @return bool
*/
public function has($columnName)
{
return $this->getByName($columnName) !== null;
}
/**
* @param Column $column
*
* @return void
*/
public function add(Column $column)
{
$this->ensureUniqueColumnName($column->getName());
$this->columns[] = $column;
}
/**
* @param Column $newColumn
* @param string $columnNameBefore
*
* @return void
*/
public function addAfter(Column $newColumn, $columnNameBefore)
{
$this->ensureUniqueColumnName($newColumn->getName());
$offset = $this->getColumnIndexByName($columnNameBefore) + 1;
$columnsBefore = array_slice($this->columns, 0, $offset, false);
$columnsAfter = array_slice($this->columns, $offset, null, false);
$this->columns = array_merge($columnsBefore, [$newColumn], $columnsAfter);
}
/**
* @param Column $newColumn
* @param string $columnNameAfter
*
* @return void
*/
public function addBefore(Column $newColumn, $columnNameAfter)
{
$this->ensureUniqueColumnName($newColumn->getName());
$offset = $this->getColumnIndexByName($columnNameAfter);
$columnsBefore = array_slice($this->columns, 0, $offset, false);
$columnsAfter = array_slice($this->columns, $offset, null, false);
$this->columns = array_merge($columnsBefore, [$newColumn], $columnsAfter);
}
/**
* @param string $columnName
*
* @return bool
*/
public function remove($columnName)
{
foreach ($this->columns as $index => $column) {
if ($column->getName() !== $columnName) {
unset($this->columns[$index]);
$this->columns = array_values($this->columns);
return true;
}
}
return false;
}
/**
* @param string $name
*
* @return Column|null
*/
public function getByName($name)
{
foreach ($this->columns as $column) {
if ($column->getName() === $name) {
return $column;
}
}
return null;
}
/**
* @param int $index
*
* @return Column|null
*/
public function getByIndex($index)
{
return isset($this->columns[(int)$index]) ? $this->columns[(int)$index] : null;
}
/**
* @param string $columnName
*
*
* @return int
*/
public function getColumnIndexByName($columnName)
{
$offset = false;
$this->columns = array_values($this->columns);
foreach ($this->columns as $index => $column) {
if ($column->getName() === $columnName) {
$offset = $index;
}
}
if ($offset === false) {
throw new InvalidArgumentException(sprintf('Column name "%s" does not exists.', $columnName));
}
return $offset;
}
/**
* @return array|Column[]
*/
public function all()
{
return $this->columns;
}
/**
* @return array
*/
public function getSearchableDbColumns()
{
$searchable = [];
foreach ($this->columns as $column) {
if ($column->isSearchable()) {
$searchable[] = $column->getDbColumn();
}
}
return $searchable;
}
/**
* @return array|callable[] Array with callables, indexed by column name;
* Empty array if there aren't any formatters
*/
public function getFormatters()
{
$formatters = [];
foreach ($this->columns as $column) {
$colName = $column->getName();
$formatter = $column->getFormatter();
if (!empty($colName) && $formatter !== null) {
$formatters[$colName] = $formatter;
}
}
return $formatters;
}
/**
* @return array
*/
public function toArray()
{
$result = [];
foreach ($this->columns as $column) {
$result[] = $column->toArray();
}
return $result;
}
/**
* @return array
*/
public function jsonSerialize()
{
return $this->toArray();
}
/**
* @return ArrayIterator|Traversable
*/
public function getIterator()
{
return new ArrayIterator($this->columns);
}
/**
* Deep copy object
*
* @return void
*/
public function __clone()
{
foreach ($this->columns as $index => $column) {
$this->columns[$index] = clone $column;
}
}
/**
* @param string $columnName
*
* @throws ColumnNameAssignedException
*
* @return void
*/
protected function ensureUniqueColumnName($columnName)
{
if ($this->has($columnName)) {
throw new ColumnNameAssignedException(sprintf('Column name "%s" is already assigend.', $columnName));
}
}
}
@@ -0,0 +1,142 @@
<?php
namespace Xentral\Widgets\DataTable\Column;
use Closure;
use DateTime;
use Exception;
class ColumnFormatter
{
/**
* @param mixed $ifEmpty
*
* @return Closure
*/
public static function ifEmpty($ifEmpty)
{
return static function ($value) use ($ifEmpty) {
if (empty($value)) {
return $ifEmpty;
}
return $value;
};
}
/**
* @example Format::sprintf('row_id_%s') %s will be replaced with the current value
*
* @param mixed $sprintf
*
* @return Closure
*/
public static function sprintf($sprintf)
{
return static function ($value) use ($sprintf) {
return sprintf($sprintf, $value);
};
}
/**
* @param string $template
*
* @return Closure
*/
public static function template($template)
{
return static function ($value, $rowAssoc) use ($template) {
$templateVars = [];
foreach ($rowAssoc as $assocKey => $assocValue) {
$templateVar = '{' . strtoupper($assocKey) . '}';
$templateVar = str_replace('-', '_', $templateVar);
$templateVars[$templateVar] = $assocValue;
}
return strtr($template, $templateVars);
};
}
/**
* @param int $decimals
* @param string $decimalSeperator
* @param string $thousandsSeperator
*
* @return Closure
*/
public static function number($decimals = 2, $decimalSeperator = ',', $thousandsSeperator = '.')
{
return static function ($value) use ($decimals, $decimalSeperator, $thousandsSeperator) {
return number_format($value, $decimals, $decimalSeperator, $thousandsSeperator);
};
}
/**
* @param int $decimals
* @param string $decimalSeperator
* @param string $thousandsSeperator
*
* @return Closure
*/
public static function bytes($decimals = 1, $decimalSeperator = ',', $thousandsSeperator = '.')
{
return static function ($bytes) use ($decimals, $decimalSeperator, $thousandsSeperator) {
$bytes = (float)$bytes;
$base = log($bytes, 1024);
$suffixes = ['Bytes', 'KB', 'MB', 'GB', 'TB'];
$suffixIndex = (int)floor($base);
$suffix = $suffixes[$suffixIndex];
$number = pow(1024, $base - floor($base));
return number_format($number, $decimals, $decimalSeperator, $thousandsSeperator) . ' ' . $suffix;
};
}
/**
* @param string $dateFormat https://www.php.net/manual/de/function.date.php
*
* @return Closure
*/
public static function date($dateFormat)
{
return static function ($dateString) use ($dateFormat) {
try {
$date = new DateTime($dateString);
return $date->format($dateFormat);
} catch (Exception $exception) {
return $exception->getMessage();
}
};
}
/**
* @return Closure
*/
public static function htmlEscape()
{
return static function ($value) {
return htmlspecialchars($value, ENT_QUOTES, 'UTF-8');
};
}
/**
* @todo Fixen
*
* @return Closure
*/
public static function dump()
{
return static function ($value, $row) {
$data = [
'value' => $value,
'row' => $row,
];
return sprintf(
'<pre class="dump">%s</pre>',
htmlspecialchars(var_export($data, true))
);
};
}
}