Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Revert fields to original types #138

Open
wants to merge 3 commits into
base: 3.x
Choose a base branch
from
Open
Show file tree
Hide file tree
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
8 changes: 8 additions & 0 deletions _build/resolvers/tables.resolver.php
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,14 @@
$manager->createObjectContainer($obj);
}

// Set to fatal errors only while updating database, to avoid false positives displayed.
$modx->setLogLevel(modX::LOG_LEVEL_FATAL);

// VersionX 3.1.1
// These fields are added to keep track of data types to be used when reverting
$manager->addField('vxDeltaField', 'before_type', ['after' => 'field_type']);
$manager->addField('vxDeltaField', 'after_type', ['after' => 'before_type']);

$modx->setLogLevel($loglevel);

break;
Expand Down
6 changes: 6 additions & 0 deletions _build/schema/versionx.mysql.schema.xml
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,12 @@
<field key="field" dbtype="varchar" precision="128" phptype="string" null="false" />
<!-- Support different field types that may render differently, e.g. image, binary, commerce_product.. -->
<field key="field_type" dbtype="varchar" precision="128" phptype="string" null="false" default="text" />
<!--
Keep track of the before and after value types so reverting doesn't decode an intended json string,
or cast an int as a string etc. Empty value means it's a string.
-->
<field key="before_type" dbtype="varchar" precision="7" phptype="string" null="false" default="" />
<field key="after_type" dbtype="varchar" precision="7" phptype="string" null="false" default="" />

<field key="before" dbtype="mediumtext" phptype="string" null="false" default="" />
<field key="after" dbtype="mediumtext" phptype="string" null="false" default="" />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,8 @@
'delta' => 0,
'field' => NULL,
'field_type' => 'text',
'before_type' => '',
'after_type' => '',
'before' => '',
'after' => '',
),
Expand Down Expand Up @@ -63,6 +65,22 @@
'null' => false,
'default' => 'text',
),
'before_type' =>
array (
'dbtype' => 'varchar',
'precision' => '7',
'phptype' => 'string',
'null' => false,
'default' => '',
),
'after_type' =>
array (
'dbtype' => 'varchar',
'precision' => '7',
'phptype' => 'string',
'null' => false,
'default' => '',
),
'before' =>
array (
'dbtype' => 'mediumtext',
Expand Down
24 changes: 20 additions & 4 deletions core/components/versionx/src/DeltaManager.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,13 @@

use Carbon\Carbon;
use Jfcherng\Diff\DiffHelper;
use modmore\VersionX\Fields\Field;
use modmore\VersionX\Types\Type;
use modmore\VersionX\Enums\RevertAction;
use MODX\Revolution\modX;

class DeltaManager {
class DeltaManager
{
public VersionX $versionX;
/** @var \modX|modX */
public $modx;
Expand All @@ -30,7 +32,6 @@ class DeltaManager {
'showHeader' => false,
];


function __construct(VersionX $versionX)
{
$this->versionX = $versionX;
Expand Down Expand Up @@ -117,13 +118,26 @@ public function createDelta(int $id, Type $type, bool $isSnapshot = false): ?\vx
$fieldType = $type->getFieldClass($field);
$fieldTypeObj = new $fieldType($value);

//
$value = Utils::flattenArray($fieldTypeObj->getValue());
// Get the value and the value type
$value = $fieldTypeObj->getValue();
$valueType = gettype($value);
// If the value is not an accepted type, default to string
if (!in_array(strtolower($valueType), Field::ACCEPTED_VALUE_TYPES)) {
$valueType = '';
}

if (is_array($value) || is_object($value)) {
$value = json_encode($value);
} else {
$value = (string)$value;
}

// If a previous delta exists, get the "after" value. Otherwise, use a blank string.
$prevValue = '';
$prevValueType = '';
if ($prevDelta && isset($prevFields[$field])) {
$prevValue = $prevFields[$field]->get('after');
$prevValueType = $prevFields[$field]->get('after_type');
}

try {
Expand All @@ -139,6 +153,8 @@ public function createDelta(int $id, Type $type, bool $isSnapshot = false): ?\vx
$deltaField = $this->modx->newObject(\vxDeltaField::class, [
'field' => $field,
'field_type' => $fieldType,
'before_type' => $prevValueType,
'after_type' => $valueType,
'before' => $prevValue,
'after' => $value,
'diff' => $renderedDiff, // Not persisted. Kept on object until cached.
Expand Down
12 changes: 12 additions & 0 deletions core/components/versionx/src/Fields/Field.php
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,18 @@ abstract class Field
protected array $options = [];
protected string $tpl = '';

public const ACCEPTED_VALUE_TYPES = [
'array',
'object',
'boolean',
'bool',
'integer',
'int',
'float',
'double',
'null'
];

function __construct($value, $name = '', $options = [])
{
if (!$this->value) {
Expand Down
30 changes: 28 additions & 2 deletions core/components/versionx/src/Fields/Properties.php
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ public function parse()
}

/**
*
* @param array $arrayField
* @param string $name
* @param array $fields
Expand All @@ -21,6 +22,10 @@ public static function splitPropertyValues(array $arrayField, string $name = '',
{
$arrays = [];
foreach ($arrayField as $field => $value) {
if (empty($name)) {
$fields[$field] = $value;
continue;
}
if (is_numeric($field)) {
$fields[$name][$field] = $value;
continue;
Expand All @@ -47,15 +52,36 @@ public static function splitPropertyValues(array $arrayField, string $name = '',
*/
public static function revertPropertyValue(\vxDeltaField $field, &$data)
{
if (!is_array($data)) {
return $data;
}

$pieces = explode('.', $field->get('field'));
$last = end($pieces);
foreach ($pieces as $piece) {
if (!is_array($data) || !array_key_exists($piece, $data)) {
if (!array_key_exists($piece, $data)) {
continue;
}

// The last 'piece' will be the key we're after.
if ($piece === $last) {
$data[$piece] = $field->get('before');
$beforeValue = $field->get('before');
$beforeType = $field->get('before_type');

if (in_array($beforeType, ['array', 'object'])) {
// Decode if it's meant to be an array/object
$decoded = json_decode($beforeValue, true);
$data[$piece] = $decoded ?: $field->get('before');
}
else if (in_array(strtolower($beforeType), self::ACCEPTED_VALUE_TYPES)) {
// Cast as the set type
$data[$piece] = settype($beforeValue, $beforeType);
}
else {
// If we're here treat as a string
$data[$piece] = $field->get('before');
}

}
else {
$data = &$data[$piece];
Expand Down
4 changes: 2 additions & 2 deletions core/components/versionx/src/Types/Type.php
Original file line number Diff line number Diff line change
Expand Up @@ -184,7 +184,7 @@ public function afterDeltaCreate(\vxDelta $delta, \xPDOObject $object): ?\vxDelt
}

/**
* Runs before object being reverted is saved.
* Runs after main object revert, and before the object is saved.
* @param string $action - 'all', 'delta', or 'single'
* @param array $fields - the delta fields that are being saved to the object
* @param \xPDOObject $object - the object being reverted
Expand Down Expand Up @@ -287,7 +287,7 @@ protected function savePropertiesFields(\vxDeltaField $field, \xPDOObject $objec
) {
// Take current properties field value and insert the "before" version at matching array keys.
$data = $object->get($propField);
Properties::revertPropertyValue($field, $data, 'before');
Properties::revertPropertyValue($field, $data);
$object->set($propField, $data);
$object->save();
}
Expand Down
8 changes: 5 additions & 3 deletions core/components/versionx/src/Utils.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@

namespace modmore\VersionX;

class Utils {

class Utils
{
/**
* Flattens an array recursively, and returns other values as a string
* @param mixed $array
Expand All @@ -12,7 +12,9 @@ class Utils {
*/
public static function flattenArray($array = []): string
{
if (!is_array($array)) return (string)$array;
if (!is_array($array)) {
return (string)$array;
}

$string = [];
foreach ($array as $key => $value) {
Expand Down