Merge branch '1.6' of github.com:getgrav/grav into 1.6

This commit is contained in:
Andy Miller
2018-09-25 15:57:46 -06:00
5 changed files with 111 additions and 31 deletions

View File

@@ -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

View File

@@ -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);
}
}
}
}

View File

@@ -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) {

View File

@@ -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']);

View File

@@ -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;
}
}