datatable.directory codebase
https://datatable.directory/
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
226 lines
6.2 KiB
226 lines
6.2 KiB
<?php
|
|
|
|
namespace App\Tables;
|
|
|
|
use Illuminate\Contracts\Support\Arrayable;
|
|
use JsonSerializable;
|
|
use MightyPork\Exceptions\SimpleValidationException;
|
|
use MightyPork\Exceptions\NotApplicableException;
|
|
use MightyPork\Utils\Utils;
|
|
|
|
/**
|
|
* Helper class representing one column in a data table.
|
|
*
|
|
* @property-read bool $id_modified
|
|
* @property-read bool $type_modified
|
|
* @property-read bool $name_modified
|
|
* @property-read bool $title_modified
|
|
*
|
|
* @property-read string $id_orig
|
|
* @property-read string $type_orig
|
|
* @property-read string $name_orig
|
|
* @property-read string $title_orig
|
|
*/
|
|
class Column implements JsonSerializable, Arrayable
|
|
{
|
|
const colTypes = [
|
|
'int', 'bool', 'float', 'string'
|
|
];
|
|
|
|
// marked public to make keyBy() work
|
|
|
|
public $id;
|
|
public $type;
|
|
public $name;
|
|
public $title;
|
|
|
|
/** @var bool - column is marked to be deleted by a changeset */
|
|
public $toRemove = false;
|
|
|
|
/** @var bool - column is new in this changeset */
|
|
public $isNew = false;
|
|
|
|
/** @var array - original attrib values if edited in a changeset */
|
|
private $orig_attribs = [];
|
|
/** @var array - list of attrib names that are modified by a changeset */
|
|
private $modified_attribs = [];
|
|
|
|
/**
|
|
* Mark for removal (used in editing GUI)
|
|
*/
|
|
public function markForRemoval()
|
|
{
|
|
$this->toRemove = true;
|
|
}
|
|
|
|
/**
|
|
* Mark this column as new
|
|
*/
|
|
public function markAsNew()
|
|
{
|
|
$this->isNew = true;
|
|
}
|
|
|
|
/**
|
|
* Modify by a changeset
|
|
*
|
|
* @param array $columnObject
|
|
*/
|
|
public function modifyByChangeset(array $columnObject)
|
|
{
|
|
foreach ((array)$columnObject as $key => $value) {
|
|
if ($value != $this->$key) {
|
|
$this->modified_attribs[] = $key;
|
|
$this->orig_attribs[$key] = $this->$key;
|
|
$this->$key = $value;
|
|
}
|
|
}
|
|
}
|
|
|
|
public function __get($name)
|
|
{
|
|
if (ends_with($name, '_modified')) {
|
|
$basename = str_replace('_modified', '', $name);
|
|
if (property_exists($this, $basename)) {
|
|
return in_array($basename, $this->modified_attribs);
|
|
}
|
|
}
|
|
|
|
if (ends_with($name, '_orig')) {
|
|
$basename = str_replace('_orig', '', $name);
|
|
if (property_exists($this, $basename)) {
|
|
return $this->orig_attribs[$basename];
|
|
}
|
|
}
|
|
|
|
throw new NotApplicableException("No such column property: $name");
|
|
}
|
|
|
|
/**
|
|
* @param $columns
|
|
* @return Column[]
|
|
*/
|
|
public static function columnsFromJson($columns)
|
|
{
|
|
if (is_string($columns)) {
|
|
$columns = json_decode($columns);
|
|
}
|
|
|
|
return array_map(function ($x) {
|
|
return new Column($x);
|
|
}, $columns);
|
|
}
|
|
|
|
/**
|
|
* Set column ID
|
|
* @param string $id - GCID
|
|
*/
|
|
public function setID($id)
|
|
{
|
|
$this->id = $id;
|
|
}
|
|
|
|
/**
|
|
* Create from object or array
|
|
*
|
|
* @param object|array $obj
|
|
*/
|
|
public function __construct($obj)
|
|
{
|
|
$b = objBag($obj);
|
|
|
|
if (!$b->has('name') || $b->name == '') {
|
|
throw new SimpleValidationException('name', "Missing column name.");
|
|
}
|
|
|
|
if (!$b->has('type') || !in_array($b->type, self::colTypes)) {
|
|
throw new SimpleValidationException('type', "Missing or invalid column type.");
|
|
}
|
|
|
|
if ($b->name[0] == '_' || !preg_match(IDENTIFIER_PATTERN, $b->name)) {
|
|
throw new SimpleValidationException('name', "Column name can contain only letters, digits, and underscore, and must start with a letter.");
|
|
}
|
|
|
|
if (!$b->has('id') || $b->id[0] == '_') {
|
|
throw new SimpleValidationException('id', "Invalid or missing column ID");
|
|
}
|
|
|
|
$this->id = $b->id;
|
|
$this->name = $b->name;
|
|
$this->type = $b->type;
|
|
$this->title = $b->title ?: $b->name;
|
|
}
|
|
|
|
/**
|
|
* @return array with keys {name, title, type}
|
|
*/
|
|
public function toArray($decorate=true)
|
|
{
|
|
if ($decorate) {
|
|
return [
|
|
'id' => $this->id,
|
|
'name' => $this->name,
|
|
'title' => $this->title,
|
|
'type' => $this->type,
|
|
'_new' => $this->isNew,
|
|
'_remove' => $this->toRemove,
|
|
'_changed' => $this->modified_attribs,
|
|
'_orig' => $this->orig_attribs,
|
|
];
|
|
} else {
|
|
return [
|
|
'id' => $this->id,
|
|
'name' => $this->name,
|
|
'title' => $this->title,
|
|
'type' => $this->type,
|
|
];
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Convert a value to the target type, validating it in the process
|
|
*
|
|
* @param mixed $value
|
|
* @return bool|float|int|string
|
|
*/
|
|
public function cast($value)
|
|
{
|
|
switch ($this->type) {
|
|
case 'int':
|
|
if (is_null($value)) return 0;
|
|
if (is_int($value)) return $value;
|
|
if (is_float($value)) return round($value);
|
|
if (is_numeric($value)) return intval($value);
|
|
throw new SimpleValidationException($this->id, "Could not convert value \"$value\" to int!");
|
|
|
|
case 'float':
|
|
if (is_null($value)) return 0;
|
|
if (is_int($value) || is_float($value)) return (float)$value;
|
|
if (is_numeric($value)) return floatval($value);
|
|
throw new SimpleValidationException($this->id, "Could not convert value \"$value\" to float!");
|
|
|
|
case 'bool':
|
|
if (is_null($value)) return false;
|
|
return Utils::parseBool($value);
|
|
|
|
case 'string':
|
|
if (is_null($value)) return "";
|
|
return "$value";
|
|
|
|
default:
|
|
throw new \LogicException("Illegal column type: \"$this->type\"");
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Specify data which should be serialized to JSON
|
|
* @link http://php.net/manual/en/jsonserializable.jsonserialize.php
|
|
* @return mixed data which can be serialized by <b>json_encode</b>,
|
|
* which is a value of any type other than a resource.
|
|
* @since 5.4.0
|
|
*/
|
|
public function jsonSerialize()
|
|
{
|
|
return $this->toArray();
|
|
}
|
|
}
|
|
|