Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
115 changes: 109 additions & 6 deletions src/sprout/Helpers/Record.php
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,15 @@
*/
namespace Sprout\Helpers;

use JsonException;
use karmabunny\kb\Collection;
use karmabunny\kb\Reflect;
use karmabunny\pdb\Models\PdbColumn;
use karmabunny\pdb\Pdb as PdbInstance;
use karmabunny\pdb\PdbModelInterface;
use karmabunny\pdb\PdbModelTrait;
use ReflectionNamedType;
use ReflectionProperty;


/**
Expand Down Expand Up @@ -58,16 +62,115 @@ public function getSaveData(): array
{
$data = Reflect::getProperties($this, null);

// Unset any data keys prefixed with an underscore
foreach ($data as $key => $value) {
if (strpos($key, '_') === 0) {
unset($data[$key]);
} else if(is_array($data[$key])) {
$data[$key] = json_encode($data[$key]);
foreach ($data as $field => &$value) {
// Exclude any properties prefixed with an underscore
if (strpos($field, '_') === 0) {
unset($data[$field]);
continue;
}

if (!is_array($value)) {
continue;
}

// Convert array data to SET or JSON-encoded string
if (static::fieldIsSet($field)) {
$value = implode(',', $value);
} else {
$value = json_encode($value);
}
}

unset($data['id']);
return $data;
}


/**
* Get the field definitions for the table that holds this record
*
* @return array<string, PdbColumn>
*/
protected static function fieldList(): array
{
static $fieldList = [];

$table = static::getTableName();
if (!isset($fieldList[$table])) {
$pdb = static::getConnection();
$fieldList[$table] = $pdb->fieldList($table);
}
return $fieldList[$table];
}


/**
* Check if a field is of the type SET(...)
*/
protected static function fieldIsSet(string $field_name): bool
{
$fields = static::fieldList();
$field_defn = $fields[$field_name]['type'] ?? null;
if ($field_defn === null) {
return false;
}
return strtolower(substr($field_defn, 0, 4) === 'set(');
}


/**
* Convert a property value to an array where expected
*
* E.g. from a JSON-encoded string, or a comma-separated list of SET elements
*
* @throws JsonException
*/
protected function convertArrayValue(string $property, mixed &$value): void
{
$type = (new ReflectionProperty($this, $property))->getType();
if (is_array($value) || (!$type instanceof ReflectionNamedType) || $type->getName() !== 'array') {
return;
}

if ($value === '' || $value === null) {
if ($type->allowsNull()) {
$value = null;
} else {
$value = [];
}
return;
}

if (static::fieldIsSet($property)) {
$value = explode(',', $value);
return;
}

// N.B. data source (e.g. MySQL JSON column) should always provide
// valid JSON, so Json::decode should never throw an exception,
// outside of memory/depth constraints
$value = Json::decode($value);

// Gracefully handle change from single value to multi-value column
if (is_scalar($value)) {
$value = [$value];
}
}

/**
*
* @param iterable $config
* @return void
* @throws JsonException
*/
public function update($config)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would be good to chuck a @inheritdoc in here.

Actually we could start using the new #[\Override] attribute, which might communicate things even better.

{
foreach ($config as $key => &$item) {
if (!property_exists($this, $key)) {
continue;
}
$this->convertArrayValue($key, $item);
}
parent::update($config);
}
}