mirror of
https://github.com/getgrav/grav.git
synced 2025-10-26 07:56:07 +01:00
Move BlueprintForm class into toolbox
This commit is contained in:
50
composer.lock
generated
50
composer.lock
generated
@@ -637,12 +637,12 @@
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/rockettheme/toolbox.git",
|
||||
"reference": "cfb20f0396f1dc8e556cdf0e785f311e10742eee"
|
||||
"reference": "687ca3b95950a07eb0d11f04f0ff0a1a0fab0b49"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/rockettheme/toolbox/zipball/cfb20f0396f1dc8e556cdf0e785f311e10742eee",
|
||||
"reference": "cfb20f0396f1dc8e556cdf0e785f311e10742eee",
|
||||
"url": "https://api.github.com/repos/rockettheme/toolbox/zipball/687ca3b95950a07eb0d11f04f0ff0a1a0fab0b49",
|
||||
"reference": "687ca3b95950a07eb0d11f04f0ff0a1a0fab0b49",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@@ -652,7 +652,7 @@
|
||||
"symfony/yaml": ">2.5"
|
||||
},
|
||||
"require-dev": {
|
||||
"phpunit/phpunit": "~5.1"
|
||||
"phpunit/phpunit": "~5.1.5"
|
||||
},
|
||||
"type": "library",
|
||||
"autoload": {
|
||||
@@ -677,20 +677,20 @@
|
||||
"php",
|
||||
"rockettheme"
|
||||
],
|
||||
"time": "2016-02-25 18:01:13"
|
||||
"time": "2016-02-29 18:27:06"
|
||||
},
|
||||
{
|
||||
"name": "symfony/console",
|
||||
"version": "v2.8.2",
|
||||
"version": "v2.8.3",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/console.git",
|
||||
"reference": "d0239fb42f98dd02e7d342f793c5d2cdee0c478d"
|
||||
"reference": "56cc5caf051189720b8de974e4746090aaa10d44"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/symfony/console/zipball/d0239fb42f98dd02e7d342f793c5d2cdee0c478d",
|
||||
"reference": "d0239fb42f98dd02e7d342f793c5d2cdee0c478d",
|
||||
"url": "https://api.github.com/repos/symfony/console/zipball/56cc5caf051189720b8de974e4746090aaa10d44",
|
||||
"reference": "56cc5caf051189720b8de974e4746090aaa10d44",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@@ -737,20 +737,20 @@
|
||||
],
|
||||
"description": "Symfony Console Component",
|
||||
"homepage": "https://symfony.com",
|
||||
"time": "2016-01-14 08:33:16"
|
||||
"time": "2016-02-28 16:20:50"
|
||||
},
|
||||
{
|
||||
"name": "symfony/event-dispatcher",
|
||||
"version": "v2.8.2",
|
||||
"version": "v2.8.3",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/event-dispatcher.git",
|
||||
"reference": "ee278f7c851533e58ca307f66305ccb9188aceda"
|
||||
"reference": "78c468665c9568c3faaa9c416a7134308f2d85c3"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/symfony/event-dispatcher/zipball/ee278f7c851533e58ca307f66305ccb9188aceda",
|
||||
"reference": "ee278f7c851533e58ca307f66305ccb9188aceda",
|
||||
"url": "https://api.github.com/repos/symfony/event-dispatcher/zipball/78c468665c9568c3faaa9c416a7134308f2d85c3",
|
||||
"reference": "78c468665c9568c3faaa9c416a7134308f2d85c3",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@@ -797,7 +797,7 @@
|
||||
],
|
||||
"description": "Symfony EventDispatcher Component",
|
||||
"homepage": "https://symfony.com",
|
||||
"time": "2016-01-13 10:28:07"
|
||||
"time": "2016-01-27 05:14:19"
|
||||
},
|
||||
{
|
||||
"name": "symfony/polyfill-iconv",
|
||||
@@ -919,16 +919,16 @@
|
||||
},
|
||||
{
|
||||
"name": "symfony/var-dumper",
|
||||
"version": "v2.8.2",
|
||||
"version": "v2.8.3",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/var-dumper.git",
|
||||
"reference": "ab94426d127ad9e95433778a3a451fe9d18f3d6b"
|
||||
"reference": "19b697abe08833ddf38c3ab0cb1bfad236b13bde"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/symfony/var-dumper/zipball/ab94426d127ad9e95433778a3a451fe9d18f3d6b",
|
||||
"reference": "ab94426d127ad9e95433778a3a451fe9d18f3d6b",
|
||||
"url": "https://api.github.com/repos/symfony/var-dumper/zipball/19b697abe08833ddf38c3ab0cb1bfad236b13bde",
|
||||
"reference": "19b697abe08833ddf38c3ab0cb1bfad236b13bde",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@@ -978,20 +978,20 @@
|
||||
"debug",
|
||||
"dump"
|
||||
],
|
||||
"time": "2016-01-07 13:38:40"
|
||||
"time": "2016-02-13 09:21:29"
|
||||
},
|
||||
{
|
||||
"name": "symfony/yaml",
|
||||
"version": "v2.8.2",
|
||||
"version": "v2.8.3",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/yaml.git",
|
||||
"reference": "34c8a4b51e751e7ea869b8262f883d008a2b81b8"
|
||||
"reference": "2a4ee40acb880c56f29fb1b8886e7ffe94f3b995"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/symfony/yaml/zipball/34c8a4b51e751e7ea869b8262f883d008a2b81b8",
|
||||
"reference": "34c8a4b51e751e7ea869b8262f883d008a2b81b8",
|
||||
"url": "https://api.github.com/repos/symfony/yaml/zipball/2a4ee40acb880c56f29fb1b8886e7ffe94f3b995",
|
||||
"reference": "2a4ee40acb880c56f29fb1b8886e7ffe94f3b995",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@@ -1027,7 +1027,7 @@
|
||||
],
|
||||
"description": "Symfony Yaml Component",
|
||||
"homepage": "https://symfony.com",
|
||||
"time": "2016-01-13 10:28:07"
|
||||
"time": "2016-02-23 07:41:20"
|
||||
},
|
||||
{
|
||||
"name": "twig/twig",
|
||||
|
||||
@@ -3,9 +3,7 @@ namespace Grav\Common\Data;
|
||||
|
||||
use Grav\Common\File\CompiledYamlFile;
|
||||
use Grav\Common\Grav;
|
||||
use RocketTheme\Toolbox\ArrayTraits\Export;
|
||||
use RocketTheme\Toolbox\ArrayTraits\ExportInterface;
|
||||
use RocketTheme\Toolbox\ArrayTraits\NestedArrayAccessWithGetters;
|
||||
use RocketTheme\Toolbox\Blueprints\BlueprintForm;
|
||||
use RocketTheme\Toolbox\ResourceLocator\UniformResourceLocator;
|
||||
|
||||
/**
|
||||
|
||||
@@ -1,483 +0,0 @@
|
||||
<?php
|
||||
namespace Grav\Common\Data;
|
||||
|
||||
use RocketTheme\Toolbox\ArrayTraits\Export;
|
||||
use RocketTheme\Toolbox\ArrayTraits\ExportInterface;
|
||||
use RocketTheme\Toolbox\ArrayTraits\NestedArrayAccessWithGetters;
|
||||
|
||||
/**
|
||||
* The Config class contains configuration information.
|
||||
*
|
||||
* @author RocketTheme
|
||||
*/
|
||||
abstract class BlueprintForm implements \ArrayAccess, ExportInterface
|
||||
{
|
||||
use NestedArrayAccessWithGetters, Export;
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
protected $items;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected $filename;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected $context;
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
protected $overrides = [];
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
protected $dynamic = [];
|
||||
|
||||
/**
|
||||
* Load file and return its contents.
|
||||
*
|
||||
* @param string $filename
|
||||
* @return string
|
||||
*/
|
||||
abstract protected function loadFile($filename);
|
||||
|
||||
/**
|
||||
* Get list of blueprint form files (file and its parents for overrides).
|
||||
*
|
||||
* @param string|array $path
|
||||
* @param string $context
|
||||
* @return array
|
||||
*/
|
||||
abstract protected function getFiles($path, $context = null);
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param string|array $filename
|
||||
* @param array $items
|
||||
*/
|
||||
public function __construct($filename, array $items = [])
|
||||
{
|
||||
$this->filename = $filename;
|
||||
$this->items = $items;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set context for import@ and extend@.
|
||||
*
|
||||
* @param $context
|
||||
* @return $this
|
||||
*/
|
||||
public function setContext($context)
|
||||
{
|
||||
$this->context = $context;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set custom overrides for import@ and extend@.
|
||||
*
|
||||
* @param array $overrides
|
||||
* @return $this
|
||||
*/
|
||||
public function setOverrides($overrides)
|
||||
{
|
||||
$this->overrides = $overrides;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Load blueprint.
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function load()
|
||||
{
|
||||
// Only load and extend blueprint if it has not yet been loaded.
|
||||
if (empty($this->items)) {
|
||||
// Get list of files.
|
||||
$files = $this->getFiles($this->filename);
|
||||
|
||||
// Load and extend blueprints.
|
||||
$data = $this->doLoad($files);
|
||||
|
||||
$this->items = array_shift($data);
|
||||
|
||||
foreach ($data as $content) {
|
||||
$this->extend($content, true);
|
||||
}
|
||||
}
|
||||
|
||||
// Import blueprints.
|
||||
$this->deepInit($this->items);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize blueprints with its dynamic fields.
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function init()
|
||||
{
|
||||
foreach ($this->dynamic as $key => $data) {
|
||||
// Locate field.
|
||||
$path = explode('/', $key);
|
||||
$current = &$this->items;
|
||||
foreach ($path as $field) {
|
||||
if (is_object($current)) {
|
||||
// Handle objects.
|
||||
if (!isset($current->{$field})) {
|
||||
$current->{$field} = array();
|
||||
}
|
||||
$current = &$current->{$field};
|
||||
} else {
|
||||
// Handle arrays and scalars.
|
||||
if (!is_array($current)) {
|
||||
$current = array($field => array());
|
||||
} elseif (!isset($current[$field])) {
|
||||
$current[$field] = array();
|
||||
}
|
||||
$current = &$current[$field];
|
||||
}
|
||||
}
|
||||
|
||||
// Set dynamic property.
|
||||
foreach ($data as $property => $call) {
|
||||
$action = 'dynamic' . ucfirst($call['action']);
|
||||
|
||||
if (method_exists($this, $action)) {
|
||||
$this->{$action}($current, $property, $call);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Get form.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function form()
|
||||
{
|
||||
return (array) $this->get('form');
|
||||
}
|
||||
|
||||
/**
|
||||
* Get form fields.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function fields()
|
||||
{
|
||||
return (array) $this->get('form.fields');
|
||||
}
|
||||
|
||||
/**
|
||||
* Extend blueprint with another blueprint.
|
||||
*
|
||||
* @param BlueprintForm|array $extends
|
||||
* @param bool $append
|
||||
* @return $this
|
||||
*/
|
||||
public function extend($extends, $append = false)
|
||||
{
|
||||
if ($extends instanceof BlueprintForm) {
|
||||
$extends = $extends->toArray();
|
||||
}
|
||||
|
||||
if ($append) {
|
||||
$a = $this->items;
|
||||
$b = $extends;
|
||||
} else {
|
||||
$a = $extends;
|
||||
$b = $this->items;
|
||||
}
|
||||
|
||||
$this->items = $this->deepMerge($a, $b);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $name
|
||||
* @param mixed $value
|
||||
* @param string $separator
|
||||
* @param bool $append
|
||||
* @return $this
|
||||
*/
|
||||
public function embed($name, $value, $separator = '/', $append = false)
|
||||
{
|
||||
$oldValue = $this->get($name, null, $separator);
|
||||
|
||||
if (is_array($oldValue) && is_array($value)) {
|
||||
if ($append) {
|
||||
$a = $oldValue;
|
||||
$b = $value;
|
||||
} else {
|
||||
$a = $value;
|
||||
$b = $oldValue;
|
||||
}
|
||||
|
||||
$value = $this->deepMerge($a, $b);
|
||||
}
|
||||
|
||||
$this->set($name, $value, $separator);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get blueprints by using dot notation for nested arrays/objects.
|
||||
*
|
||||
* @example $value = $this->resolve('this.is.my.nested.variable');
|
||||
* returns ['this.is.my', 'nested.variable']
|
||||
*
|
||||
* @param array $path
|
||||
* @param string $separator
|
||||
* @return array
|
||||
*/
|
||||
public function resolve(array $path, $separator = '/')
|
||||
{
|
||||
$fields = false;
|
||||
$parts = [];
|
||||
$current = $this['form.fields'];
|
||||
$result = [null, null, null];
|
||||
|
||||
while (($field = current($path)) !== null) {
|
||||
if (!$fields && isset($current['fields'])) {
|
||||
if (!empty($current['array'])) {
|
||||
$result = [$current, $parts, $path ? implode($separator, $path) : null];
|
||||
// Skip item offset.
|
||||
$parts[] = array_shift($path);
|
||||
}
|
||||
|
||||
$current = $current['fields'];
|
||||
$fields = true;
|
||||
|
||||
} elseif (isset($current[$field])) {
|
||||
$parts[] = array_shift($path);
|
||||
$current = $current[$field];
|
||||
$fields = false;
|
||||
|
||||
} elseif (isset($current['.' . $field])) {
|
||||
$parts[] = array_shift($path);
|
||||
$current = $current['.' . $field];
|
||||
$fields = false;
|
||||
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Deep merge two arrays together.
|
||||
*
|
||||
* @param array $a
|
||||
* @param array $b
|
||||
* @return array
|
||||
*/
|
||||
protected function deepMerge(array $a, array $b)
|
||||
{
|
||||
$bref_stack = array(&$a);
|
||||
$head_stack = array($b);
|
||||
|
||||
do {
|
||||
end($bref_stack);
|
||||
$bref = &$bref_stack[key($bref_stack)];
|
||||
$head = array_pop($head_stack);
|
||||
unset($bref_stack[key($bref_stack)]);
|
||||
|
||||
foreach (array_keys($head) as $key) {
|
||||
if (isset($key, $bref[$key]) && is_array($bref[$key]) && is_array($head[$key])) {
|
||||
$bref_stack[] = &$bref[$key];
|
||||
$head_stack[] = $head[$key];
|
||||
} else {
|
||||
$bref = array_merge($bref, [$key => $head[$key]]);
|
||||
}
|
||||
}
|
||||
} while (count($head_stack));
|
||||
|
||||
return $a;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $items
|
||||
* @param array $path
|
||||
* @return string
|
||||
*/
|
||||
protected function deepInit(array &$items, $path = [])
|
||||
{
|
||||
$ordering = '';
|
||||
$order = [];
|
||||
$field = end($path) === 'fields';
|
||||
|
||||
foreach ($items as $key => &$item) {
|
||||
// Set name for nested field.
|
||||
if ($field && isset($item['type'])) {
|
||||
$item['name'] = $key;
|
||||
}
|
||||
|
||||
// Handle special instructions in the form.
|
||||
if (!empty($key) && ($key[0] === '@' || $key[strlen($key) - 1] === '@')) {
|
||||
$name = trim($key, '@');
|
||||
|
||||
switch ($name) {
|
||||
case 'import':
|
||||
$this->doImport($item, $path);
|
||||
unset($items[$key]);
|
||||
break;
|
||||
case 'ordering':
|
||||
$ordering = $item;
|
||||
unset($items[$key]);
|
||||
break;
|
||||
default:
|
||||
$list = explode('-', trim($name, '@'), 2);
|
||||
$action = array_shift($list);
|
||||
$property = array_shift($list);
|
||||
|
||||
$this->dynamic[implode('/', $path)][$property] = ['action' => $action, 'params' => $item];
|
||||
}
|
||||
|
||||
} elseif (is_array($item)) {
|
||||
// Recursively initialize form.
|
||||
$newPath = array_merge($path, [$key]);
|
||||
|
||||
$location = $this->deepInit($item, $newPath);
|
||||
if ($location) {
|
||||
$order[$key] = $location;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ($order) {
|
||||
// Reorder fields if needed.
|
||||
$items = $this->doReorder($items, $order);
|
||||
}
|
||||
|
||||
return $ordering;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $value
|
||||
* @param array $path
|
||||
*/
|
||||
protected function doImport(array &$value, array &$path)
|
||||
{
|
||||
$type = !is_string($value) ? !isset($value['type']) ? null : $value['type'] : $value;
|
||||
|
||||
$files = $this->getFiles($type, isset($value['context']) ? $value['context'] : null);
|
||||
|
||||
if (!$files) {
|
||||
return;
|
||||
}
|
||||
|
||||
/** @var BlueprintForm $blueprint */
|
||||
$blueprint = new static($files);
|
||||
$blueprint->setContext($this->context)->setOverrides($this->overrides)->load();
|
||||
|
||||
$name = implode('/', $path);
|
||||
|
||||
$this->embed($name, $blueprint->form(), '/', false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Internal function that handles loading extended blueprints.
|
||||
*
|
||||
* @param array $files
|
||||
* @return array
|
||||
*/
|
||||
protected function doLoad(array $files)
|
||||
{
|
||||
$filename = array_shift($files);
|
||||
$content = $this->loadFile($filename);
|
||||
|
||||
$extends = isset($content['@extends']) ? (array) $content['@extends']
|
||||
: (isset($content['extends@']) ? (array) $content['extends@'] : null);
|
||||
|
||||
$data = isset($extends) ? $this->doExtend($files, $extends) : [];
|
||||
$data[] = $content;
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Internal function to recursively load extended blueprints.
|
||||
*
|
||||
* @param array $parents
|
||||
* @param array $extends
|
||||
* @return array
|
||||
*/
|
||||
protected function doExtend(array $parents, array $extends)
|
||||
{
|
||||
if (is_string(key($extends))) {
|
||||
$extends = [$extends];
|
||||
}
|
||||
|
||||
$data = [];
|
||||
foreach ($extends as $value) {
|
||||
// Accept array of type and context or a string.
|
||||
$type = !is_string($value)
|
||||
? !isset($value['type']) ? null : $value['type'] : $value;
|
||||
|
||||
if (!$type) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if ($type === '@parent' || $type === 'parent@') {
|
||||
$files = $parents;
|
||||
} else {
|
||||
$files = $this->getFiles($type, isset($value['context']) ? $value['context'] : null);
|
||||
}
|
||||
|
||||
if ($files) {
|
||||
$data = array_merge($data, $this->doLoad($files));
|
||||
}
|
||||
}
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Internal function to reorder items.
|
||||
*
|
||||
* @param array $items
|
||||
* @param array $keys
|
||||
* @return array
|
||||
*/
|
||||
protected function doReorder(array $items, array $keys)
|
||||
{
|
||||
$reordered = array_keys($items);
|
||||
|
||||
foreach ($keys as $item => $ordering) {
|
||||
if ((string)(int) $ordering === (string) $ordering) {
|
||||
$location = array_search($item, $reordered);
|
||||
$rel = array_splice($reordered, $location, 1);
|
||||
array_splice($reordered, $ordering, 0, $rel);
|
||||
|
||||
} elseif (isset($items[$ordering])) {
|
||||
$location = array_search($item, $reordered);
|
||||
$rel = array_splice($reordered, $location, 1);
|
||||
$location = array_search($ordering, $reordered);
|
||||
array_splice($reordered, $location + 1, 0, $rel);
|
||||
}
|
||||
}
|
||||
|
||||
return array_merge(array_flip($reordered), $items);
|
||||
}
|
||||
}
|
||||
@@ -4,7 +4,7 @@ namespace Grav\Common\Data;
|
||||
use Grav\Common\Grav;
|
||||
use RocketTheme\Toolbox\ArrayTraits\Export;
|
||||
use RocketTheme\Toolbox\ArrayTraits\ExportInterface;
|
||||
use RocketTheme\Toolbox\Blueprints\Blueprints as BaseBlueprints;
|
||||
use RocketTheme\Toolbox\Blueprints\BlueprintSchema as BlueprintSchemaBase;
|
||||
|
||||
/**
|
||||
* Blueprint schema handles the internal logic of blueprints.
|
||||
@@ -12,7 +12,7 @@ use RocketTheme\Toolbox\Blueprints\Blueprints as BaseBlueprints;
|
||||
* @author RocketTheme
|
||||
* @license MIT
|
||||
*/
|
||||
class BlueprintSchema extends BaseBlueprints implements ExportInterface
|
||||
class BlueprintSchema extends BlueprintSchemaBase implements ExportInterface
|
||||
{
|
||||
use Export;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user