mirror of
https://github.com/getgrav/grav.git
synced 2026-07-10 02:32:33 +02:00
Merge branch '1.6' of github.com:getgrav/grav into 1.6
This commit is contained in:
@@ -15,6 +15,7 @@
|
||||
* Added `Grav\Framework\Collection\AbstractIndexCollection` class
|
||||
* Added `Grav\Framework\Object\ObjectIndex` class
|
||||
* Added `Grav\Framework\Flex` classes
|
||||
* Added proper support for hiding form fields in blueprints by using dynamic property like `security@: admin.foobar` to any field
|
||||
1. [](#improved)
|
||||
* Doctrine filecache is now namespaced with prefix to support purging
|
||||
|
||||
|
||||
@@ -10,6 +10,7 @@ namespace Grav\Common\Data;
|
||||
|
||||
use Grav\Common\File\CompiledYamlFile;
|
||||
use Grav\Common\Grav;
|
||||
use Grav\Common\User\User;
|
||||
use RocketTheme\Toolbox\Blueprints\BlueprintForm;
|
||||
use RocketTheme\Toolbox\ResourceLocator\UniformResourceLocator;
|
||||
|
||||
@@ -252,4 +253,45 @@ class Blueprint extends BlueprintForm
|
||||
$field[$property] = $config;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $field
|
||||
* @param string $property
|
||||
* @param array $call
|
||||
*/
|
||||
protected function dynamicSecurity(array &$field, $property, array &$call)
|
||||
{
|
||||
if ($property) {
|
||||
return;
|
||||
}
|
||||
|
||||
$grav = Grav::instance();
|
||||
$actions = (array)$call['params'];
|
||||
|
||||
/** @var User $user */
|
||||
if (isset($grav['user'])) {
|
||||
$user = Grav::instance()['user'] ?? null;
|
||||
foreach ($actions as $action) {
|
||||
if (!$user->authorize($action)) {
|
||||
$this->addPropertyRecursive($field, 'validate', ['ignore' => true]);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected function addPropertyRecursive(array &$field, $property, $value)
|
||||
{
|
||||
if (\is_array($value) && isset($field[$property]) && \is_array($field[$property])) {
|
||||
$field[$property] = array_merge_recursive($field[$property], $value);
|
||||
} else {
|
||||
$field[$property] = $value;
|
||||
}
|
||||
|
||||
if (!empty($field['fields'])) {
|
||||
foreach ($field['fields'] as $key => &$child) {
|
||||
$this->addPropertyRecursive($child, $property, $value);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -49,20 +49,20 @@ class BlueprintSchema extends BlueprintSchemaBase implements ExportInterface
|
||||
/**
|
||||
* Filter data by using blueprints.
|
||||
*
|
||||
* @param array $data
|
||||
* @param array $data Incoming data, for example from a form.
|
||||
* @param bool $missingValuesAsNull Include missing values as nulls.
|
||||
* @return array
|
||||
*/
|
||||
public function filter(array $data)
|
||||
public function filter(array $data, $missingValuesAsNull = false)
|
||||
{
|
||||
return $this->filterArray($data, $this->nested);
|
||||
return $this->filterArray($data, $this->nested, $missingValuesAsNull);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $data
|
||||
* @param array $rules
|
||||
* @returns array
|
||||
* @return array
|
||||
* @throws \RuntimeException
|
||||
* @internal
|
||||
*/
|
||||
protected function validateArray(array $data, array $rules)
|
||||
{
|
||||
@@ -74,6 +74,11 @@ class BlueprintSchema extends BlueprintSchemaBase implements ExportInterface
|
||||
|
||||
if ($rule) {
|
||||
// Item has been defined in blueprints.
|
||||
if (!empty($rule['validate']['ignore'])) {
|
||||
// Skip validation in the ignored field.
|
||||
continue;
|
||||
}
|
||||
|
||||
$messages += Validation::validate($field, $rule);
|
||||
} elseif (\is_array($field) && \is_array($val)) {
|
||||
// Array has been defined in blueprints.
|
||||
@@ -90,22 +95,42 @@ class BlueprintSchema extends BlueprintSchemaBase implements ExportInterface
|
||||
/**
|
||||
* @param array $data
|
||||
* @param array $rules
|
||||
* @param bool $missingValuesAsNull
|
||||
* @return array
|
||||
* @internal
|
||||
*/
|
||||
protected function filterArray(array $data, array $rules)
|
||||
protected function filterArray(array $data, array $rules, $missingValuesAsNull)
|
||||
{
|
||||
$results = [];
|
||||
|
||||
if ($missingValuesAsNull) {
|
||||
// First pass is to fill up all the fields with null. This is done to lock the ordering of the fields.
|
||||
foreach ($rules as $key => $rule) {
|
||||
if ($key && !isset($results[$key])) {
|
||||
$val = $rules[$key] ?? $rules['*'] ?? null;
|
||||
$rule = \is_string($val) ? $this->items[$val] : null;
|
||||
|
||||
if (empty($rule['validate']['ignore'])) {
|
||||
$results[$key] = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
foreach ($data as $key => $field) {
|
||||
$val = $rules[$key] ?? $rules['*'] ?? null;
|
||||
$rule = \is_string($val) ? $this->items[$val] : null;
|
||||
|
||||
if ($rule) {
|
||||
// Item has been defined in blueprints.
|
||||
if (!empty($rule['validate']['ignore'])) {
|
||||
// Skip any data in the ignored field.
|
||||
continue;
|
||||
}
|
||||
|
||||
$field = Validation::filter($field, $rule);
|
||||
} elseif (\is_array($field) && \is_array($val)) {
|
||||
// Array has been defined in blueprints.
|
||||
$field = $this->filterArray($field, $val);
|
||||
$field = $this->filterArray($field, $val, $missingValuesAsNull);
|
||||
} elseif (isset($rules['validation']) && $rules['validation'] === 'strict') {
|
||||
$field = null;
|
||||
}
|
||||
@@ -133,6 +158,13 @@ class BlueprintSchema extends BlueprintSchemaBase implements ExportInterface
|
||||
}
|
||||
|
||||
$field = $this->items[$field];
|
||||
|
||||
// Skip ignored field, it will not be required.
|
||||
if (!empty($field['validate']['ignore'])) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Check if required.
|
||||
if (isset($field['validate']['required'])
|
||||
&& $field['validate']['required'] === true) {
|
||||
|
||||
|
||||
@@ -45,12 +45,12 @@ class FlexObject implements FlexObjectInterface, FlexAuthorizeInterface
|
||||
|
||||
/** @var FlexDirectory */
|
||||
private $_flexDirectory;
|
||||
/** @var string */
|
||||
private $storageKey;
|
||||
/** @var int */
|
||||
private $timestamp = 0;
|
||||
/** @var FlexForm[] */
|
||||
private $forms = [];
|
||||
private $_forms = [];
|
||||
/** @var string */
|
||||
private $_storageKey;
|
||||
/** @var int */
|
||||
private $_timestamp = 0;
|
||||
|
||||
/**
|
||||
* @return array
|
||||
@@ -116,18 +116,23 @@ class FlexObject implements FlexObjectInterface, FlexAuthorizeInterface
|
||||
*/
|
||||
public function update(array $data, $isFullUpdate = false)
|
||||
{
|
||||
// Validate and filter the incoming data.
|
||||
$blueprint = $this->getFlexDirectory()->getBlueprint();
|
||||
$blueprint->validate($data + ['storage_key' => $this->getStorageKey(), 'timestamp' => $this->getTimestamp()]);
|
||||
$data = $blueprint->filter($data);
|
||||
|
||||
if (!$isFullUpdate) {
|
||||
// Partial update: merge data to the existing object.
|
||||
$elements = $this->getElements();
|
||||
$data = $blueprint->mergeData($elements, $data);
|
||||
}
|
||||
|
||||
$blueprint->validate($data + ['storage_key' => $this->getStorageKey()]);
|
||||
$data = $blueprint->filter($data);
|
||||
|
||||
// Filter object data.
|
||||
$this->filterElements($data);
|
||||
$this->setElements($data);
|
||||
|
||||
if ($data) {
|
||||
$this->setElements($data);
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
@@ -165,11 +170,11 @@ class FlexObject implements FlexObjectInterface, FlexAuthorizeInterface
|
||||
*/
|
||||
public function getForm($name = 'default')
|
||||
{
|
||||
if (!isset($this->forms[$name])) {
|
||||
$this->forms[$name] = new FlexForm($name, $this);
|
||||
if (!isset($this->_forms[$name])) {
|
||||
$this->_forms[$name] = new FlexForm($name, $this);
|
||||
}
|
||||
|
||||
return $this->forms[$name];
|
||||
return $this->_forms[$name];
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -212,7 +217,7 @@ class FlexObject implements FlexObjectInterface, FlexAuthorizeInterface
|
||||
*/
|
||||
public function getStorageKey()
|
||||
{
|
||||
return $this->storageKey;
|
||||
return $this->_storageKey;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -221,7 +226,7 @@ class FlexObject implements FlexObjectInterface, FlexAuthorizeInterface
|
||||
*/
|
||||
public function setStorageKey($key = null)
|
||||
{
|
||||
$this->storageKey = $key;
|
||||
$this->_storageKey = $key;
|
||||
|
||||
return $this;
|
||||
}
|
||||
@@ -231,7 +236,7 @@ class FlexObject implements FlexObjectInterface, FlexAuthorizeInterface
|
||||
*/
|
||||
public function getTimestamp() : int
|
||||
{
|
||||
return $this->timestamp;
|
||||
return $this->_timestamp;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -240,7 +245,7 @@ class FlexObject implements FlexObjectInterface, FlexAuthorizeInterface
|
||||
*/
|
||||
public function setTimestamp($timestamp = null)
|
||||
{
|
||||
$this->timestamp = $timestamp ?? time();
|
||||
$this->_timestamp = $timestamp ?? time();
|
||||
|
||||
return $this;
|
||||
}
|
||||
@@ -485,8 +490,8 @@ class FlexObject implements FlexObjectInterface, FlexAuthorizeInterface
|
||||
throw new \InvalidArgumentException("Cannot unserialize '{$type}': Not found");
|
||||
}
|
||||
$this->_flexDirectory = $directory;
|
||||
$this->storageKey = $serialized['storage_key'];
|
||||
$this->timestamp = $serialized['storage_timestamp'];
|
||||
$this->_storageKey = $serialized['storage_key'];
|
||||
$this->_timestamp = $serialized['storage_timestamp'];
|
||||
|
||||
$this->setKey($serialized['key']);
|
||||
$this->setElements($serialized['elements']);
|
||||
@@ -571,10 +576,10 @@ class FlexObject implements FlexObjectInterface, FlexAuthorizeInterface
|
||||
protected function filterElements(array &$elements)
|
||||
{
|
||||
if (!empty($elements['storage_key'])) {
|
||||
$this->storageKey = trim($elements['storage_key']);
|
||||
$this->_storageKey = trim($elements['storage_key']);
|
||||
}
|
||||
if (!empty($elements['storage_timestamp'])) {
|
||||
$this->timestamp = (int)$elements['storage_timestamp'];
|
||||
$this->_timestamp = (int)$elements['storage_timestamp'];
|
||||
}
|
||||
|
||||
unset ($elements['storage_key'], $elements['storage_timestamp']);
|
||||
|
||||
@@ -19,7 +19,7 @@ use Grav\Common\User\User;
|
||||
*/
|
||||
trait FlexAuthorizeTrait
|
||||
{
|
||||
private $authorize = '%s.flex-object.%s';
|
||||
private $_authorize = '%s.flex-object.%s';
|
||||
|
||||
public function authorize(string $action, string $scope = null) : bool
|
||||
{
|
||||
@@ -34,11 +34,11 @@ trait FlexAuthorizeTrait
|
||||
$action = $this->exists() ? 'update' : 'create';
|
||||
}
|
||||
|
||||
return $user->authorize(sprintf($this->authorize, $scope, $action)) || $user->authorize('admin.super');
|
||||
return $user->authorize(sprintf($this->_authorize, $scope, $action)) || $user->authorize('admin.super');
|
||||
}
|
||||
|
||||
protected function setAuthorizeRule(string $authorize) : void
|
||||
{
|
||||
$this->authorize = $authorize;
|
||||
$this->_authorize = $authorize;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user