mirror of
https://github.com/getgrav/grav.git
synced 2026-03-22 04:21:37 +01:00
Fixed FlexObject::update() removing fields which aren't allowed by ACL
This commit is contained in:
@@ -6,6 +6,7 @@
|
||||
1. [](#bugfix)
|
||||
* Fixed `FlexUser` loosing ACL information
|
||||
* Fixed `FlexUser::find()` breaking when nothing is found
|
||||
* Fixed `FlexObject::update()` removing fields which aren't allowed by ACL
|
||||
|
||||
# v1.6.0-rc.3
|
||||
## 02/18/2019
|
||||
|
||||
@@ -121,15 +121,31 @@ class Blueprint extends BlueprintForm
|
||||
*
|
||||
* @param array $data
|
||||
* @param bool $missingValuesAsNull
|
||||
* @param bool $keepEmptyValues
|
||||
* @return array
|
||||
*/
|
||||
public function filter(array $data, bool $missingValuesAsNull = false)
|
||||
public function filter(array $data, bool $missingValuesAsNull = false, bool $keepEmptyValues = false)
|
||||
{
|
||||
$this->initInternals();
|
||||
|
||||
return $this->blueprintSchema->filter($data, $missingValuesAsNull);
|
||||
return $this->blueprintSchema->filter($data, $missingValuesAsNull, $keepEmptyValues);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Flatten data by using blueprints.
|
||||
*
|
||||
* @param array $data
|
||||
* @return array
|
||||
*/
|
||||
public function flattenData(array $data)
|
||||
{
|
||||
$this->initInternals();
|
||||
|
||||
return $this->blueprintSchema->flattenData($data);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Return blueprint data schema.
|
||||
*
|
||||
|
||||
@@ -79,11 +79,51 @@ class BlueprintSchema extends BlueprintSchemaBase implements ExportInterface
|
||||
*
|
||||
* @param array $data Incoming data, for example from a form.
|
||||
* @param bool $missingValuesAsNull Include missing values as nulls.
|
||||
* @param bool $keepEmptyValues Include empty values.
|
||||
* @return array
|
||||
*/
|
||||
public function filter(array $data, $missingValuesAsNull = false)
|
||||
public function filter(array $data, $missingValuesAsNull = false, $keepEmptyValues = false)
|
||||
{
|
||||
return $this->filterArray($data, $this->nested, $missingValuesAsNull);
|
||||
return $this->filterArray($data, $this->nested, $missingValuesAsNull, $keepEmptyValues);
|
||||
}
|
||||
|
||||
/**
|
||||
* Flatten data by using blueprints.
|
||||
*
|
||||
* @param array $data Data to be flattened.
|
||||
* @return array
|
||||
*/
|
||||
public function flattenData(array $data)
|
||||
{
|
||||
return $this->flattenArray($data, $this->nested, '');
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $data
|
||||
* @param array $rules
|
||||
* @param string $prefix
|
||||
* @return array
|
||||
*/
|
||||
protected function flattenArray(array $data, array $rules, string $prefix)
|
||||
{
|
||||
$array = [];
|
||||
|
||||
foreach ($data as $key => $field) {
|
||||
$val = $rules[$key] ?? $rules['*'] ?? null;
|
||||
$rule = is_string($val) ? $this->items[$val] : null;
|
||||
|
||||
if ($rule || isset($val['*'])) {
|
||||
// Item has been defined in blueprints.
|
||||
$array[$prefix.$key] = $field;
|
||||
} elseif (is_array($field) && is_array($val)) {
|
||||
// Array has been defined in blueprints.
|
||||
$array += $this->flattenArray($field, $val, $prefix . $key . '.');
|
||||
} else {
|
||||
// Undefined/extra item.
|
||||
$array[$prefix.$key] = $field;
|
||||
}
|
||||
}
|
||||
return $array;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -124,9 +164,10 @@ class BlueprintSchema extends BlueprintSchemaBase implements ExportInterface
|
||||
* @param array $data
|
||||
* @param array $rules
|
||||
* @param bool $missingValuesAsNull
|
||||
* @param bool $keepEmptyValues
|
||||
* @return array
|
||||
*/
|
||||
protected function filterArray(array $data, array $rules, $missingValuesAsNull)
|
||||
protected function filterArray(array $data, array $rules, $missingValuesAsNull, $keepEmptyValues)
|
||||
{
|
||||
$results = [];
|
||||
|
||||
@@ -138,7 +179,7 @@ class BlueprintSchema extends BlueprintSchemaBase implements ExportInterface
|
||||
$rule = \is_string($val) ? $this->items[$val] : null;
|
||||
|
||||
if (empty($rule['validate']['ignore'])) {
|
||||
$results[$key] = null;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -152,26 +193,28 @@ class BlueprintSchema extends BlueprintSchemaBase implements ExportInterface
|
||||
// Item has been defined in blueprints.
|
||||
if (!empty($rule['validate']['ignore'])) {
|
||||
// Skip any data in the ignored field.
|
||||
unset($results[$key]);
|
||||
continue;
|
||||
}
|
||||
|
||||
$field = Validation::filter($field, $rule);
|
||||
} elseif (\is_array($field) && \is_array($val)) {
|
||||
// Array has been defined in blueprints.
|
||||
$field = $this->filterArray($field, $val, $missingValuesAsNull);
|
||||
$field = $this->filterArray($field, $val, $missingValuesAsNull, $keepEmptyValues);
|
||||
|
||||
} elseif (isset($rules['validation']) && $rules['validation'] === 'strict') {
|
||||
$field = null;
|
||||
// Skip any extra data.
|
||||
continue;
|
||||
}
|
||||
|
||||
if (null !== $field && (!\is_array($field) || !empty($field))) {
|
||||
if ($keepEmptyValues || (null !== $field && (!\is_array($field) || !empty($field)))) {
|
||||
$results[$key] = $field;
|
||||
}
|
||||
}
|
||||
|
||||
return $results;
|
||||
return $results ?: null;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param array $data
|
||||
* @param array $toggles
|
||||
|
||||
@@ -197,13 +197,15 @@ class Data implements DataInterface, \ArrayAccess, \Countable, \JsonSerializable
|
||||
}
|
||||
|
||||
/**
|
||||
* @param bool $missingValuesAsNull
|
||||
* @return $this
|
||||
* Filter all items by using blueprints.
|
||||
*/
|
||||
public function filter(bool $missingValuesAsNull = false)
|
||||
public function filter()
|
||||
{
|
||||
$this->items = $this->blueprints()->filter($this->items, $missingValuesAsNull);
|
||||
$args = func_get_args();
|
||||
$missingValuesAsNull = (bool)(array_shift($args) ?: false);
|
||||
$keepEmptyValues = (bool)(array_shift($args) ?: false);
|
||||
|
||||
$this->items = $this->blueprints()->filter($this->items, $missingValuesAsNull, $keepEmptyValues);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
@@ -150,48 +150,6 @@ class User extends FlexObject implements UserInterface, MediaManipulationInterfa
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $data
|
||||
* @param array $files
|
||||
* @return $this
|
||||
* @throws ValidationException
|
||||
*/
|
||||
public function update(array $data, array $files = [])
|
||||
{
|
||||
if ($data) {
|
||||
// Filter updated data.
|
||||
$this->filterElements($data);
|
||||
|
||||
// Merge data to the existing object.
|
||||
$elements = $this->getElements();
|
||||
|
||||
// Validate and filter the incoming data.
|
||||
$blueprint = $this->getFlexDirectory()->getBlueprint();
|
||||
|
||||
// Merge existing object to the data.
|
||||
$data = $blueprint->mergeData($elements, $data);
|
||||
|
||||
// Validate and filter elements and throw an error if any issues were found.
|
||||
$blueprint->validate($data + ['storage_key' => $this->getStorageKey(), 'timestamp' => $this->getTimestamp()]);
|
||||
$data = $blueprint->filter($data);
|
||||
|
||||
// Make sure that we add missing (filtered by ACL) elements back.
|
||||
$data = $blueprint->mergeData($elements, $data);
|
||||
|
||||
// Store the changes
|
||||
$this->_changes = Utils::arrayDiffMultidimensional($data, $this->getElements());
|
||||
|
||||
// Finally update the object.
|
||||
$this->setElements($data);
|
||||
}
|
||||
|
||||
if ($files && method_exists($this, 'setUpdatedMedia')) {
|
||||
$this->setUpdatedMedia($files);
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get value from a page variable (used mostly for creating edit forms).
|
||||
*
|
||||
|
||||
@@ -255,7 +255,7 @@ class FlexForm implements FlexFormInterface
|
||||
protected function filterData(\ArrayAccess $data): void
|
||||
{
|
||||
if ($data instanceof Data) {
|
||||
$data->filter(true);
|
||||
$data->filter(true, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -117,27 +117,32 @@ class FlexObject implements FlexObjectInterface, FlexAuthorizeInterface
|
||||
public function update(array $data, array $files = [])
|
||||
{
|
||||
if ($data) {
|
||||
// Filter updated data.
|
||||
$blueprint = $this->getBlueprint();
|
||||
|
||||
// Process updated data through the object filters.
|
||||
$this->filterElements($data);
|
||||
|
||||
// Merge data to the existing object.
|
||||
// Get currently stored data.
|
||||
$elements = $this->getElements();
|
||||
|
||||
// Validate and filter the incoming data.
|
||||
$blueprint = $this->getFlexDirectory()->getBlueprint();
|
||||
|
||||
// Merge existing object to the data.
|
||||
$data = $blueprint->mergeData($elements, $data);
|
||||
// Merge existing object to the test data to be validated.
|
||||
$test = $blueprint->mergeData($elements, $data);
|
||||
|
||||
// Validate and filter elements and throw an error if any issues were found.
|
||||
$blueprint->validate($data + ['storage_key' => $this->getStorageKey(), 'timestamp' => $this->getTimestamp()]);
|
||||
$data = $blueprint->filter($data);
|
||||
|
||||
// Store the changes
|
||||
$this->_changes = Utils::arrayDiffMultidimensional($data, $this->getElements());
|
||||
$blueprint->validate($test + ['storage_key' => $this->getStorageKey(), 'timestamp' => $this->getTimestamp()]);
|
||||
$data = $blueprint->filter($data, false, true);
|
||||
|
||||
// Finally update the object.
|
||||
$this->setElements($data);
|
||||
foreach ($blueprint->flattenData($data) as $key => $value) {
|
||||
if ($value === null) {
|
||||
$this->unsetNestedProperty($key);
|
||||
} else {
|
||||
$this->setNestedProperty($key, $value);
|
||||
}
|
||||
}
|
||||
|
||||
// Store the changes
|
||||
$this->_changes = Utils::arrayDiffMultidimensional($this->getElements(), $elements);
|
||||
}
|
||||
|
||||
if ($files && method_exists($this, 'setUpdatedMedia')) {
|
||||
|
||||
Reference in New Issue
Block a user