mirror of
https://github.com/getgrav/grav.git
synced 2026-05-07 06:16:52 +02:00
Merge branches 'develop' and 'feature/blueprints-update' of https://github.com/getgrav/grav into develop
This commit is contained in:
@@ -22,7 +22,7 @@
|
||||
"mrclay/minify": "~2.2",
|
||||
"donatj/phpuseragentparser": "~0.3",
|
||||
"pimple/pimple": "~3.0",
|
||||
"rockettheme/toolbox": "~1.2",
|
||||
"rockettheme/toolbox": "dev-develop",
|
||||
"maximebf/debugbar": "~1.10",
|
||||
"ext-mbstring": "*",
|
||||
"ext-openssl": "*",
|
||||
|
||||
1596
composer.lock
generated
1596
composer.lock
generated
File diff suppressed because it is too large
Load Diff
@@ -29,7 +29,6 @@ form:
|
||||
|
||||
content:
|
||||
type: markdown
|
||||
showPreview: true
|
||||
validate:
|
||||
type: textarea
|
||||
|
||||
|
||||
@@ -19,13 +19,22 @@ form:
|
||||
|
||||
fields:
|
||||
frontmatter:
|
||||
type: frontmatter
|
||||
classes: frontmatter
|
||||
type: editor
|
||||
label: PLUGIN_ADMIN.FRONTMATTER
|
||||
|
||||
autofocus: true
|
||||
codemirror:
|
||||
mode: 'yaml'
|
||||
indentUnit: 4
|
||||
autofocus: true
|
||||
indentWithTabs: false
|
||||
lineNumbers: true
|
||||
styleActiveLine: true
|
||||
gutters: ['CodeMirror-lint-markers']
|
||||
lint: true
|
||||
|
||||
content:
|
||||
type: markdown
|
||||
showPreview: true
|
||||
|
||||
uploads:
|
||||
type: pagemedia
|
||||
|
||||
@@ -19,13 +19,22 @@ form:
|
||||
|
||||
fields:
|
||||
frontmatter:
|
||||
type: frontmatter
|
||||
classes: frontmatter
|
||||
type: editor
|
||||
label: PLUGIN_ADMIN.FRONTMATTER
|
||||
autofocus: true
|
||||
codemirror:
|
||||
mode: 'yaml'
|
||||
indentUnit: 4
|
||||
autofocus: true
|
||||
indentWithTabs: false
|
||||
lineNumbers: true
|
||||
styleActiveLine: true
|
||||
gutters: ['CodeMirror-lint-markers']
|
||||
lint: true
|
||||
|
||||
content:
|
||||
type: markdown
|
||||
showPreview: true
|
||||
|
||||
uploads:
|
||||
type: pagemedia
|
||||
|
||||
@@ -177,13 +177,14 @@ class Assets
|
||||
*/
|
||||
public function init()
|
||||
{
|
||||
$grav = Grav::instance();
|
||||
/** @var Config $config */
|
||||
$config = Grav::instance()['config'];
|
||||
$base_url = Grav::instance()['base_url'];
|
||||
$config = $grav['config'];
|
||||
$base_url = $grav['base_url'];
|
||||
$asset_config = (array)$config->get('system.assets');
|
||||
|
||||
/** @var UniformResourceLocator $locator */
|
||||
$locator = Grav::instance()['locator'];
|
||||
$locator = $grav['locator'];
|
||||
$this->assets_dir = $locator->findResource('asset://') . DS;
|
||||
$this->assets_url = $locator->findResource('asset://', false);
|
||||
|
||||
|
||||
@@ -40,10 +40,9 @@ class ZipBackup
|
||||
if (!$destination) {
|
||||
$destination = Grav::instance()['locator']->findResource('backup://', true);
|
||||
|
||||
if (!$destination)
|
||||
if (!$destination) {
|
||||
throw new \RuntimeException('The backup folder is missing.');
|
||||
|
||||
Folder::mkdir($destination);
|
||||
}
|
||||
}
|
||||
|
||||
$name = Grav::instance()['config']->get('site.title', basename(GRAV_ROOT));
|
||||
|
||||
@@ -230,27 +230,29 @@ class Cache extends Getters
|
||||
/**
|
||||
* Deletes an item in the cache based on the id
|
||||
*
|
||||
* @param $id the id of the cached data entry
|
||||
* @return bool true if the item was deleted successfully
|
||||
* @param string $id the id of the cached data entry
|
||||
* @return bool true if the item was deleted successfully
|
||||
*/
|
||||
public function delete($id)
|
||||
{
|
||||
if ($this->enabled) {
|
||||
return $this->driver->delete($id);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a boolean state of whether or not the item exists in the cache based on id key
|
||||
*
|
||||
* @param $id the id of the cached data entry
|
||||
* @return bool true if the cached items exists
|
||||
* @param string $id the id of the cached data entry
|
||||
* @return bool true if the cached items exists
|
||||
*/
|
||||
public function contains($id)
|
||||
{
|
||||
if ($this->enabled) {
|
||||
return $this->driver->contains(($id));
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -311,7 +313,7 @@ class Cache extends Getters
|
||||
$anything = true;
|
||||
}
|
||||
} elseif (is_dir($file)) {
|
||||
if (@Folder::delete($file)) {
|
||||
if (Folder::delete($file)) {
|
||||
$anything = true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -226,7 +226,7 @@ abstract class CompiledBase
|
||||
'timestamp' => time(),
|
||||
'checksum' => $this->checksum(),
|
||||
'files' => $this->files,
|
||||
'data' => $this->object->toArray()
|
||||
'data' => $this->getState()
|
||||
];
|
||||
|
||||
$file->save($cache);
|
||||
@@ -235,4 +235,9 @@ abstract class CompiledBase
|
||||
|
||||
$this->modified();
|
||||
}
|
||||
|
||||
protected function getState()
|
||||
{
|
||||
return $this->object->toArray();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
<?php
|
||||
namespace Grav\Common\Config;
|
||||
|
||||
use Grav\Common\File\CompiledYamlFile;
|
||||
use RocketTheme\Toolbox\Blueprints\Blueprints;
|
||||
use Grav\Common\Data\Blueprint;
|
||||
use Grav\Common\Data\BlueprintSchema;
|
||||
use Grav\Common\Grav;
|
||||
|
||||
/**
|
||||
* The Compiled Blueprints class.
|
||||
@@ -12,13 +13,29 @@ class CompiledBlueprints extends CompiledBase
|
||||
/**
|
||||
* @var int Version number for the compiled file.
|
||||
*/
|
||||
public $version = 1;
|
||||
public $version = 2;
|
||||
|
||||
/**
|
||||
* @var Blueprints Blueprints object.
|
||||
* @var BlueprintSchema Blueprints object.
|
||||
*/
|
||||
protected $object;
|
||||
|
||||
/**
|
||||
* Returns checksum from the configuration files.
|
||||
*
|
||||
* You can set $this->checksum = false to disable this check.
|
||||
*
|
||||
* @return bool|string
|
||||
*/
|
||||
public function checksum()
|
||||
{
|
||||
if (!isset($this->checksum)) {
|
||||
$this->checksum = md5(json_encode($this->files) . json_encode($this->getTypes()) . $this->version);
|
||||
}
|
||||
|
||||
return $this->checksum;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create configuration object.
|
||||
*
|
||||
@@ -26,24 +43,70 @@ class CompiledBlueprints extends CompiledBase
|
||||
*/
|
||||
protected function createObject(array $data = [])
|
||||
{
|
||||
$this->object = new Blueprints($data);
|
||||
$this->object = (new BlueprintSchema($data))->setTypes($this->getTypes());
|
||||
}
|
||||
|
||||
/**
|
||||
* Get list of form field types.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected function getTypes()
|
||||
{
|
||||
return Grav::instance()['plugins']->formFieldTypes ?: [];
|
||||
}
|
||||
|
||||
/**
|
||||
* Finalize configuration object.
|
||||
*/
|
||||
protected function finalizeObject() {}
|
||||
protected function finalizeObject()
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* Load single configuration file and append it to the correct position.
|
||||
*
|
||||
* @param string $name Name of the position.
|
||||
* @param string $filename File to be loaded.
|
||||
* @param array $files Files to be loaded.
|
||||
*/
|
||||
protected function loadFile($name, $filename)
|
||||
protected function loadFile($name, $files)
|
||||
{
|
||||
$file = CompiledYamlFile::instance($filename);
|
||||
$this->object->embed($name, $file->content(), '/');
|
||||
$file->free();
|
||||
// Load blueprint file.
|
||||
$blueprint = new Blueprint($files);
|
||||
|
||||
$this->object->embed($name, $blueprint->load()->toArray(), '/', true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Load and join all configuration files.
|
||||
*
|
||||
* @return bool
|
||||
* @internal
|
||||
*/
|
||||
protected function loadFiles()
|
||||
{
|
||||
$this->createObject();
|
||||
|
||||
// Convert file list into parent list.
|
||||
$list = [];
|
||||
foreach ($this->files as $files) {
|
||||
foreach ($files as $name => $item) {
|
||||
$list[$name][] = $this->path . $item['file'];
|
||||
}
|
||||
}
|
||||
|
||||
// Load files.
|
||||
foreach ($list as $name => $files) {
|
||||
$this->loadFile($name, $files);
|
||||
}
|
||||
|
||||
$this->finalizeObject();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
protected function getState()
|
||||
{
|
||||
return $this->object->getState();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,6 +4,7 @@ namespace Grav\Common\Config;
|
||||
use Grav\Common\File\CompiledYamlFile;
|
||||
use Grav\Common\Data\Data;
|
||||
use Grav\Common\Utils;
|
||||
use Pimple\Container;
|
||||
use RocketTheme\Toolbox\File\YamlFile;
|
||||
use RocketTheme\Toolbox\ResourceLocator\UniformResourceLocator;
|
||||
|
||||
@@ -113,12 +114,12 @@ class Setup extends Data
|
||||
],
|
||||
];
|
||||
|
||||
/**
|
||||
* @param Container|array $container
|
||||
*/
|
||||
public function __construct($container)
|
||||
{
|
||||
$environment = $container['uri']->environment();
|
||||
if (!$environment) {
|
||||
$environment = 'localhost';
|
||||
}
|
||||
$environment = $container['uri']->environment() ?: 'localhost';
|
||||
|
||||
// Pre-load setup.php which contains our initial configuration.
|
||||
// Configuration may contain dynamic parts, which is why we need to always load it.
|
||||
|
||||
@@ -1,87 +1,40 @@
|
||||
<?php
|
||||
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;
|
||||
|
||||
/**
|
||||
* Blueprint handles the inside logic of blueprints.
|
||||
* The Config class contains configuration information.
|
||||
*
|
||||
* @author RocketTheme
|
||||
* @license MIT
|
||||
*/
|
||||
class Blueprint implements \ArrayAccess, ExportInterface
|
||||
class Blueprint extends BlueprintForm
|
||||
{
|
||||
use Export, NestedArrayAccessWithGetters;
|
||||
|
||||
public $name;
|
||||
|
||||
public $initialized = false;
|
||||
|
||||
protected $items;
|
||||
protected $context;
|
||||
protected $fields;
|
||||
protected $rules = array();
|
||||
protected $nested = array();
|
||||
protected $filter = ['validation' => 1];
|
||||
|
||||
/**
|
||||
* @param string $name
|
||||
* @param array $data
|
||||
* @param Blueprints $context
|
||||
* @var string
|
||||
*/
|
||||
public function __construct($name, array $data = array(), Blueprints $context = null)
|
||||
{
|
||||
$this->name = $name;
|
||||
$this->items = $data;
|
||||
$this->context = $context;
|
||||
}
|
||||
protected $context = 'blueprints://';
|
||||
|
||||
/**
|
||||
* Set filter for inherited properties.
|
||||
* @var BlueprintSchema
|
||||
*/
|
||||
protected $blueprintSchema;
|
||||
|
||||
/**
|
||||
* Get nested structure containing default values defined in the blueprints.
|
||||
*
|
||||
* @param array $filter List of field names to be inherited.
|
||||
*/
|
||||
public function setFilter(array $filter)
|
||||
{
|
||||
$this->filter = array_flip($filter);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return all form fields.
|
||||
* Fields without default value are ignored in the list.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function fields()
|
||||
public function getDefaults()
|
||||
{
|
||||
if (!isset($this->fields)) {
|
||||
$this->fields = [];
|
||||
$this->embed('', $this->items);
|
||||
}
|
||||
$this->initInternals();
|
||||
|
||||
return $this->fields;
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate data against blueprints.
|
||||
*
|
||||
* @param array $data
|
||||
* @throws \RuntimeException
|
||||
*/
|
||||
public function validate(array $data)
|
||||
{
|
||||
// Initialize data
|
||||
$this->fields();
|
||||
|
||||
try {
|
||||
$this->validateArray($data, $this->nested);
|
||||
} catch (\RuntimeException $e) {
|
||||
$language = Grav::instance()['language'];
|
||||
$message = sprintf($language->translate('FORM.VALIDATION_FAIL', null, true) . ' %s', $e->getMessage());
|
||||
throw new \RuntimeException($message);
|
||||
}
|
||||
return $this->blueprintSchema->getDefaults();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -89,26 +42,15 @@ class Blueprint implements \ArrayAccess, ExportInterface
|
||||
*
|
||||
* @param array $data1
|
||||
* @param array $data2
|
||||
* @param string $name Optional
|
||||
* @param string $separator Optional
|
||||
* @return array
|
||||
*/
|
||||
public function mergeData(array $data1, array $data2)
|
||||
public function mergeData(array $data1, array $data2, $name = null, $separator = '.')
|
||||
{
|
||||
// Initialize data
|
||||
$this->fields();
|
||||
return $this->mergeArrays($data1, $data2, $this->nested);
|
||||
}
|
||||
$this->initInternals();
|
||||
|
||||
/**
|
||||
* Filter data by using blueprints.
|
||||
*
|
||||
* @param array $data
|
||||
* @return array
|
||||
*/
|
||||
public function filter(array $data)
|
||||
{
|
||||
// Initialize data
|
||||
$this->fields();
|
||||
return $this->filterArray($data, $this->nested);
|
||||
return $this->blueprintSchema->mergeData($data1, $data2, $name, $separator);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -120,357 +62,158 @@ class Blueprint implements \ArrayAccess, ExportInterface
|
||||
*/
|
||||
public function extra(array $data, $prefix = '')
|
||||
{
|
||||
// Initialize data
|
||||
$this->fields();
|
||||
$rules = $this->nested;
|
||||
$this->initInternals();
|
||||
|
||||
// Drill down to prefix level
|
||||
if (!empty($prefix)) {
|
||||
$parts = explode('.', trim($prefix, '.'));
|
||||
foreach ($parts as $part) {
|
||||
$rules = isset($rules[$part]) ? $rules[$part] : [];
|
||||
}
|
||||
}
|
||||
|
||||
return $this->extraArray($data, $rules, $prefix);
|
||||
return $this->blueprintSchema->extra($data, $prefix);
|
||||
}
|
||||
|
||||
/**
|
||||
* Extend blueprint with another blueprint.
|
||||
* Validate data against blueprints.
|
||||
*
|
||||
* @param Blueprint $extends
|
||||
* @param bool $append
|
||||
*/
|
||||
public function extend(Blueprint $extends, $append = false)
|
||||
{
|
||||
$blueprints = $append ? $this->items : $extends->toArray();
|
||||
$appended = $append ? $extends->toArray() : $this->items;
|
||||
|
||||
$bref_stack = array(&$blueprints);
|
||||
$head_stack = array($appended);
|
||||
|
||||
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, array($key => $head[$key]));
|
||||
}
|
||||
}
|
||||
} while (count($head_stack));
|
||||
|
||||
$this->items = $blueprints;
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert object into an array.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getState()
|
||||
{
|
||||
return ['name' => $this->name, 'items' => $this->items, 'rules' => $this->rules, 'nested' => $this->nested];
|
||||
}
|
||||
|
||||
/**
|
||||
* Embed an array to the blueprint.
|
||||
*
|
||||
* @param $name
|
||||
* @param array $value
|
||||
* @param string $separator
|
||||
*/
|
||||
public function embed($name, array $value, $separator = '.')
|
||||
{
|
||||
|
||||
if (!isset($value['form']['fields']) || !is_array($value['form']['fields'])) {
|
||||
return;
|
||||
}
|
||||
// Initialize data
|
||||
$this->fields();
|
||||
$prefix = $name ? strtr($name, $separator, '.') . '.' : '';
|
||||
$params = array_intersect_key($this->filter, $value);
|
||||
$this->parseFormFields($value['form']['fields'], $params, $prefix, $this->fields);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $data
|
||||
* @param array $rules
|
||||
* @param array $data
|
||||
* @throws \RuntimeException
|
||||
* @internal
|
||||
*/
|
||||
protected function validateArray(array $data, array $rules)
|
||||
public function validate(array $data)
|
||||
{
|
||||
$this->checkRequired($data, $rules);
|
||||
$this->initInternals();
|
||||
|
||||
foreach ($data as $key => $field) {
|
||||
$val = isset($rules[$key]) ? $rules[$key] : null;
|
||||
$rule = is_string($val) ? $this->rules[$val] : null;
|
||||
|
||||
if ($rule) {
|
||||
// Item has been defined in blueprints.
|
||||
Validation::validate($field, $rule);
|
||||
} elseif (is_array($field) && is_array($val)) {
|
||||
// Array has been defined in blueprints.
|
||||
$this->validateArray($field, $val);
|
||||
} elseif (isset($this->items['form']['validation']) && $this->items['form']['validation'] == 'strict') {
|
||||
// Undefined/extra item.
|
||||
throw new \RuntimeException(sprintf('%s is not defined in blueprints', $key));
|
||||
}
|
||||
}
|
||||
$this->blueprintSchema->validate($data);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $data
|
||||
* @param array $rules
|
||||
* @return array
|
||||
* @internal
|
||||
*/
|
||||
protected function filterArray(array $data, array $rules)
|
||||
{
|
||||
$results = array();
|
||||
foreach ($data as $key => $field) {
|
||||
$val = isset($rules[$key]) ? $rules[$key] : null;
|
||||
$rule = is_string($val) ? $this->rules[$val] : null;
|
||||
|
||||
if ($rule) {
|
||||
// Item has been defined in blueprints.
|
||||
$field = Validation::filter($field, $rule);
|
||||
} elseif (is_array($field) && is_array($val)) {
|
||||
// Array has been defined in blueprints.
|
||||
$field = $this->filterArray($field, $val);
|
||||
} elseif (isset($this->items['form']['validation']) && $this->items['form']['validation'] == 'strict') {
|
||||
$field = null;
|
||||
}
|
||||
|
||||
if (isset($field) && (!is_array($field) || !empty($field))) {
|
||||
$results[$key] = $field;
|
||||
}
|
||||
}
|
||||
|
||||
return $results;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $data1
|
||||
* @param array $data2
|
||||
* @param array $rules
|
||||
* @return array
|
||||
* @internal
|
||||
*/
|
||||
protected function mergeArrays(array $data1, array $data2, array $rules)
|
||||
{
|
||||
foreach ($data2 as $key => $field) {
|
||||
$val = isset($rules[$key]) ? $rules[$key] : null;
|
||||
$rule = is_string($val) ? $this->rules[$val] : null;
|
||||
|
||||
if (!$rule && array_key_exists($key, $data1) && is_array($field) && is_array($val)) {
|
||||
// Array has been defined in blueprints.
|
||||
$data1[$key] = $this->mergeArrays($data1[$key], $field, $val);
|
||||
} else {
|
||||
// Otherwise just take value from the data2.
|
||||
$data1[$key] = $field;
|
||||
}
|
||||
}
|
||||
|
||||
return $data1;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $data
|
||||
* @param array $rules
|
||||
* @param string $prefix
|
||||
* @return array
|
||||
* @internal
|
||||
*/
|
||||
protected function extraArray(array $data, array $rules, $prefix)
|
||||
{
|
||||
$array = array();
|
||||
foreach ($data as $key => $field) {
|
||||
$val = isset($rules[$key]) ? $rules[$key] : null;
|
||||
$rule = is_string($val) ? $this->rules[$val] : null;
|
||||
|
||||
if ($rule) {
|
||||
// Item has been defined in blueprints.
|
||||
} elseif (is_array($field) && is_array($val)) {
|
||||
// Array has been defined in blueprints.
|
||||
$array += $this->ExtraArray($field, $val, $prefix . $key . '.');
|
||||
} else {
|
||||
// Undefined/extra item.
|
||||
$array[$prefix.$key] = $field;
|
||||
}
|
||||
}
|
||||
return $array;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets all field definitions from the blueprints.
|
||||
*
|
||||
* @param array $fields
|
||||
* @param array $params
|
||||
* @param string $prefix
|
||||
* @param array $current
|
||||
* @internal
|
||||
*/
|
||||
protected function parseFormFields(array &$fields, $params, $prefix, array &$current)
|
||||
{
|
||||
// Go though all the fields in current level.
|
||||
foreach ($fields as $key => &$field) {
|
||||
$current[$key] = &$field;
|
||||
// Set name from the array key.
|
||||
$field['name'] = $prefix . $key;
|
||||
$field += $params;
|
||||
|
||||
if (isset($field['fields']) && (!isset($field['type']) || $field['type'] !== 'list')) {
|
||||
// Recursively get all the nested fields.
|
||||
$newParams = array_intersect_key($this->filter, $field);
|
||||
$this->parseFormFields($field['fields'], $newParams, $prefix, $current[$key]['fields']);
|
||||
} else if ($field['type'] !== 'ignore') {
|
||||
$this->rules[$prefix . $key] = &$field;
|
||||
$this->addProperty($prefix . $key);
|
||||
|
||||
if ($field['type'] === 'list') {
|
||||
// we loop through list to get the actual field
|
||||
if (isset($field['fields']) && $field['fields']) {
|
||||
foreach($field['fields'] as $subName => &$subField) {
|
||||
$this->parseFormField($subField);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
$this->parseFormField($field);
|
||||
}
|
||||
|
||||
if (isset($field['validate']['rule']) && $field['type'] !== 'ignore') {
|
||||
$field['validate'] += $this->getRule($field['validate']['rule']);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Parses individual field definition
|
||||
*
|
||||
* @param array $field
|
||||
* @internal
|
||||
*/
|
||||
protected function parseFormField(&$field) {
|
||||
foreach ($field as $name => $value) {
|
||||
// Support nested blueprints.
|
||||
if ($this->context && $name == '@import') {
|
||||
$values = (array) $value;
|
||||
if (!isset($field['fields'])) {
|
||||
$field['fields'] = array();
|
||||
}
|
||||
foreach ($values as $bname) {
|
||||
$b = $this->context->get($bname);
|
||||
$field['fields'] = array_merge($field['fields'], $b->fields());
|
||||
}
|
||||
}
|
||||
|
||||
// Support for callable data values.
|
||||
elseif (substr($name, 0, 6) == '@data-') {
|
||||
$property = substr($name, 6);
|
||||
if (is_array($value)) {
|
||||
$func = array_shift($value);
|
||||
} else {
|
||||
$func = $value;
|
||||
$value = array();
|
||||
}
|
||||
list($o, $f) = preg_split('/::/', $func);
|
||||
if (!$f && function_exists($o)) {
|
||||
$data = call_user_func_array($o, $value);
|
||||
} elseif ($f && method_exists($o, $f)) {
|
||||
$data = call_user_func_array(array($o, $f), $value);
|
||||
}
|
||||
|
||||
// If function returns a value,
|
||||
if (isset($data)) {
|
||||
if (isset($field[$property]) && is_array($field[$property]) && is_array($data)) {
|
||||
// Combine field and @data-field together.
|
||||
$field[$property] += $data;
|
||||
} else {
|
||||
// Or create/replace field with @data-field.
|
||||
$field[$property] = $data;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
elseif (substr($name, 0, 8) == '@config-') {
|
||||
$property = substr($name, 8);
|
||||
$default = isset($field[$property]) ? $field[$property] : null;
|
||||
$config = Grav::instance()['config']->get($value, $default);
|
||||
|
||||
if (!is_null($config)) {
|
||||
$field[$property] = $config;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Add property to the definition.
|
||||
* Filter data by using blueprints.
|
||||
*
|
||||
* @param string $path Comma separated path to the property.
|
||||
* @internal
|
||||
*/
|
||||
protected function addProperty($path)
|
||||
{
|
||||
$parts = explode('.', $path);
|
||||
$item = array_pop($parts);
|
||||
|
||||
$nested = &$this->nested;
|
||||
foreach ($parts as $part) {
|
||||
if (!isset($nested[$part])) {
|
||||
$nested[$part] = array();
|
||||
}
|
||||
$nested = &$nested[$part];
|
||||
}
|
||||
|
||||
if (!isset($nested[$item])) {
|
||||
$nested[$item] = $path;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $rule
|
||||
* @param array $data
|
||||
* @return array
|
||||
* @internal
|
||||
*/
|
||||
protected function getRule($rule)
|
||||
public function filter(array $data)
|
||||
{
|
||||
if (isset($this->items['rules'][$rule]) && is_array($this->items['rules'][$rule])) {
|
||||
return $this->items['rules'][$rule];
|
||||
}
|
||||
return array();
|
||||
$this->initInternals();
|
||||
|
||||
return $this->blueprintSchema->filter($data);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $data
|
||||
* @param array $fields
|
||||
* @throws \RuntimeException
|
||||
* @internal
|
||||
* Initialize validator.
|
||||
*/
|
||||
protected function checkRequired(array $data, array $fields)
|
||||
protected function initInternals()
|
||||
{
|
||||
foreach ($fields as $name => $field) {
|
||||
if (!is_string($field)) {
|
||||
continue;
|
||||
if (!isset($this->blueprintSchema)) {
|
||||
$types = Grav::instance()['plugins']->formFieldTypes;
|
||||
|
||||
$this->blueprintSchema = new BlueprintSchema;
|
||||
if ($types) {
|
||||
$this->blueprintSchema->setTypes($types);
|
||||
}
|
||||
$field = $this->rules[$field];
|
||||
if (isset($field['validate']['required'])
|
||||
&& $field['validate']['required'] === true
|
||||
&& empty($data[$name])) {
|
||||
$value = isset($field['label']) ? $field['label'] : $field['name'];
|
||||
$language = Grav::instance()['language'];
|
||||
$message = sprintf($language->translate('FORM.MISSING_REQUIRED_FIELD', null, true) . ' %s', $value);
|
||||
throw new \RuntimeException($message);
|
||||
$this->blueprintSchema->embed('', $this->items);
|
||||
$this->blueprintSchema->init();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $filename
|
||||
* @return string
|
||||
*/
|
||||
protected function loadFile($filename)
|
||||
{
|
||||
$file = CompiledYamlFile::instance($filename);
|
||||
$content = $file->content();
|
||||
$file->free();
|
||||
|
||||
return $content;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string|array $path
|
||||
* @param string $context
|
||||
* @return array
|
||||
*/
|
||||
protected function getFiles($path, $context = null)
|
||||
{
|
||||
if (is_string($path) && !strpos($path, '://')) {
|
||||
// Resolve filename.
|
||||
if (isset($this->overrides[$path])) {
|
||||
$path = $this->overrides[$path];
|
||||
} else {
|
||||
if ($context === null) {
|
||||
$context = $this->context;
|
||||
}
|
||||
if ($context && $context[strlen($context)-1] !== '/') {
|
||||
$context .= '/';
|
||||
}
|
||||
$path = $context . $path;
|
||||
|
||||
if (!preg_match('/\.yaml$/', $path)) {
|
||||
$path .= '.yaml';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (is_string($path) && strpos($path, '://')) {
|
||||
/** @var UniformResourceLocator $locator */
|
||||
$locator = Grav::instance()['locator'];
|
||||
|
||||
$files = $locator->findResources($path);
|
||||
} else {
|
||||
$files = (array) $path;
|
||||
}
|
||||
|
||||
return $files;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $field
|
||||
* @param string $property
|
||||
* @param array $call
|
||||
*/
|
||||
protected function dynamicData(array &$field, $property, array &$call)
|
||||
{
|
||||
$params = $call['params'];
|
||||
|
||||
if (is_array($params)) {
|
||||
$function = array_shift($params);
|
||||
} else {
|
||||
$function = $params;
|
||||
$params = [];
|
||||
}
|
||||
|
||||
list($o, $f) = preg_split('/::/', $function, 2);
|
||||
if (!$f) {
|
||||
if (function_exists($o)) {
|
||||
$data = call_user_func_array($o, $params);
|
||||
}
|
||||
} else {
|
||||
if (method_exists($o, $f)) {
|
||||
$data = call_user_func_array(array($o, $f), $params);
|
||||
}
|
||||
}
|
||||
|
||||
// If function returns a value,
|
||||
if (isset($data)) {
|
||||
if (isset($field[$property]) && is_array($field[$property]) && is_array($data)) {
|
||||
// Combine field and @data-field together.
|
||||
$field[$property] += $data;
|
||||
} else {
|
||||
// Or create/replace field with @data-field.
|
||||
$field[$property] = $data;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $field
|
||||
* @param string $property
|
||||
* @param array $call
|
||||
*/
|
||||
protected function dynamicConfig(array &$field, $property, array &$call)
|
||||
{
|
||||
$value = $call['params'];
|
||||
|
||||
$default = isset($field[$property]) ? $field[$property] : null;
|
||||
$config = Grav::instance()['config']->get($value, $default);
|
||||
|
||||
if (!is_null($config)) {
|
||||
$field[$property] = $config;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
164
system/src/Grav/Common/Data/BlueprintSchema.php
Normal file
164
system/src/Grav/Common/Data/BlueprintSchema.php
Normal file
@@ -0,0 +1,164 @@
|
||||
<?php
|
||||
namespace Grav\Common\Data;
|
||||
|
||||
use Grav\Common\Grav;
|
||||
use RocketTheme\Toolbox\ArrayTraits\Export;
|
||||
use RocketTheme\Toolbox\ArrayTraits\ExportInterface;
|
||||
use RocketTheme\Toolbox\Blueprints\BlueprintSchema as BlueprintSchemaBase;
|
||||
|
||||
/**
|
||||
* Blueprint schema handles the internal logic of blueprints.
|
||||
*
|
||||
* @author RocketTheme
|
||||
* @license MIT
|
||||
*/
|
||||
class BlueprintSchema extends BlueprintSchemaBase implements ExportInterface
|
||||
{
|
||||
use Export;
|
||||
|
||||
protected $ignoreFormKeys = [
|
||||
'label' => true,
|
||||
'title' => true,
|
||||
'help' => true,
|
||||
'placeholder' => true,
|
||||
'placeholder_key' => true,
|
||||
'placeholder_value' => true,
|
||||
'fields' => true
|
||||
];
|
||||
|
||||
/**
|
||||
* Validate data against blueprints.
|
||||
*
|
||||
* @param array $data
|
||||
* @throws \RuntimeException
|
||||
*/
|
||||
public function validate(array $data)
|
||||
{
|
||||
try {
|
||||
$messages = $this->validateArray($data, $this->nested);
|
||||
|
||||
} catch (\RuntimeException $e) {
|
||||
throw (new ValidationException($e->getMessage(), $e->getCode(), $e))->setMessages();
|
||||
}
|
||||
|
||||
if (!empty($messages)) {
|
||||
throw (new ValidationException())->setMessages($messages);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Filter data by using blueprints.
|
||||
*
|
||||
* @param array $data
|
||||
* @return array
|
||||
*/
|
||||
public function filter(array $data)
|
||||
{
|
||||
return $this->filterArray($data, $this->nested);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $data
|
||||
* @param array $rules
|
||||
* @returns array
|
||||
* @throws \RuntimeException
|
||||
* @internal
|
||||
*/
|
||||
protected function validateArray(array $data, array $rules)
|
||||
{
|
||||
$messages = $this->checkRequired($data, $rules);
|
||||
|
||||
foreach ($data as $key => $field) {
|
||||
$val = isset($rules[$key]) ? $rules[$key] : null;
|
||||
$rule = is_string($val) ? $this->items[$val] : null;
|
||||
|
||||
if ($rule) {
|
||||
// Item has been defined in blueprints.
|
||||
$messages += Validation::validate($field, $rule);
|
||||
} elseif (is_array($field) && is_array($val)) {
|
||||
// Array has been defined in blueprints.
|
||||
$messages += $this->validateArray($field, $val);
|
||||
} elseif (isset($rules['validation']) && $rules['validation'] == 'strict') {
|
||||
// Undefined/extra item.
|
||||
throw new \RuntimeException(sprintf('%s is not defined in blueprints', $key));
|
||||
}
|
||||
}
|
||||
|
||||
return $messages;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $data
|
||||
* @param array $rules
|
||||
* @return array
|
||||
* @internal
|
||||
*/
|
||||
protected function filterArray(array $data, array $rules)
|
||||
{
|
||||
$results = array();
|
||||
foreach ($data as $key => $field) {
|
||||
$val = isset($rules[$key]) ? $rules[$key] : null;
|
||||
$rule = is_string($val) ? $this->items[$val] : null;
|
||||
|
||||
if ($rule) {
|
||||
// Item has been defined in blueprints.
|
||||
$field = Validation::filter($field, $rule);
|
||||
} elseif (is_array($field) && is_array($val)) {
|
||||
// Array has been defined in blueprints.
|
||||
$field = $this->filterArray($field, $val);
|
||||
} elseif (isset($rules['validation']) && $rules['validation'] == 'strict') {
|
||||
$field = null;
|
||||
}
|
||||
|
||||
if (isset($field) && (!is_array($field) || !empty($field))) {
|
||||
$results[$key] = $field;
|
||||
}
|
||||
}
|
||||
|
||||
return $results;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $data
|
||||
* @param array $fields
|
||||
* @return array
|
||||
*/
|
||||
protected function checkRequired(array $data, array $fields)
|
||||
{
|
||||
$messages = [];
|
||||
|
||||
foreach ($fields as $name => $field) {
|
||||
if (!is_string($field)) {
|
||||
continue;
|
||||
}
|
||||
$field = $this->items[$field];
|
||||
if (isset($field['validate']['required'])
|
||||
&& $field['validate']['required'] === true
|
||||
&& !isset($data[$name])) {
|
||||
$value = isset($field['label']) ? $field['label'] : $field['name'];
|
||||
$language = Grav::instance()['language'];
|
||||
$message = sprintf($language->translate('FORM.MISSING_REQUIRED_FIELD', null, true) . ' %s', $value);
|
||||
$messages[$field['name']][] = $message;
|
||||
}
|
||||
}
|
||||
|
||||
return $messages;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $field
|
||||
* @param string $property
|
||||
* @param array $call
|
||||
*/
|
||||
protected function dynamicConfig(array &$field, $property, array &$call)
|
||||
{
|
||||
$value = $call['params'];
|
||||
|
||||
$default = isset($field[$property]) ? $field[$property] : null;
|
||||
$config = Grav::instance()['config']->get($value, $default);
|
||||
|
||||
if (!is_null($config)) {
|
||||
$field[$property] = $config;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,7 +1,6 @@
|
||||
<?php
|
||||
namespace Grav\Common\Data;
|
||||
|
||||
use Grav\Common\File\CompiledYamlFile;
|
||||
use Grav\Common\Grav;
|
||||
use RocketTheme\Toolbox\ResourceLocator\UniformResourceLocator;
|
||||
|
||||
@@ -15,12 +14,12 @@ class Blueprints
|
||||
{
|
||||
protected $search;
|
||||
protected $types;
|
||||
protected $instances = array();
|
||||
protected $instances = [];
|
||||
|
||||
/**
|
||||
* @param string|array $search Search path.
|
||||
*/
|
||||
public function __construct($search)
|
||||
public function __construct($search = 'blueprints://')
|
||||
{
|
||||
$this->search = $search;
|
||||
}
|
||||
@@ -35,73 +34,7 @@ class Blueprints
|
||||
public function get($type)
|
||||
{
|
||||
if (!isset($this->instances[$type])) {
|
||||
$parents = [];
|
||||
if (is_string($this->search)) {
|
||||
$filename = $this->search . $type . YAML_EXT;
|
||||
|
||||
// Check if search is a stream and resolve the path.
|
||||
if (strpos($filename, '://')) {
|
||||
$grav = Grav::instance();
|
||||
/** @var UniformResourceLocator $locator */
|
||||
$locator = $grav['locator'];
|
||||
$parents = $locator->findResources($filename);
|
||||
$filename = array_shift($parents);
|
||||
}
|
||||
} else {
|
||||
$filename = isset($this->search[$type]) ? $this->search[$type] : '';
|
||||
}
|
||||
|
||||
if ($filename && is_file($filename)) {
|
||||
$file = CompiledYamlFile::instance($filename);
|
||||
$blueprints = $file->content();
|
||||
} else {
|
||||
$blueprints = [];
|
||||
}
|
||||
|
||||
$blueprint = new Blueprint($type, $blueprints, $this);
|
||||
|
||||
if (isset($blueprints['@extends'])) {
|
||||
// Extend blueprint by other blueprints.
|
||||
$extends = (array) $blueprints['@extends'];
|
||||
|
||||
if (is_string(key($extends))) {
|
||||
$extends = [ $extends ];
|
||||
}
|
||||
|
||||
foreach ($extends as $extendConfig) {
|
||||
$extendType = !is_string($extendConfig) ? empty($extendConfig['type']) ? false : $extendConfig['type'] : $extendConfig;
|
||||
|
||||
if (!$extendType) {
|
||||
continue;
|
||||
} elseif ($extendType === '@parent') {
|
||||
$parentFile = array_shift($parents);
|
||||
if (!$parentFile || !is_file($parentFile)) {
|
||||
continue;
|
||||
}
|
||||
$blueprints = CompiledYamlFile::instance($parentFile)->content();
|
||||
$parent = new Blueprint($type.'-parent', $blueprints, $this);
|
||||
$blueprint->extend($parent);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (is_string($extendConfig) || empty($extendConfig['context'])) {
|
||||
$context = $this;
|
||||
} else {
|
||||
// Load blueprints from external context.
|
||||
$array = explode('://', $extendConfig['context'], 2);
|
||||
$scheme = array_shift($array);
|
||||
$path = array_shift($array);
|
||||
if ($path) {
|
||||
$scheme .= '://';
|
||||
$extendType = $path ? "{$path}/{$extendType}" : $extendType;
|
||||
}
|
||||
$context = new self($scheme);
|
||||
}
|
||||
$blueprint->extend($context->get($extendType));
|
||||
}
|
||||
}
|
||||
|
||||
$this->instances[$type] = $blueprint;
|
||||
$this->instances[$type] = $this->loadFile($type);
|
||||
}
|
||||
|
||||
return $this->instances[$type];
|
||||
@@ -117,15 +50,15 @@ class Blueprints
|
||||
if ($this->types === null) {
|
||||
$this->types = array();
|
||||
|
||||
// Check if search is a stream.
|
||||
if (strpos($this->search, '://')) {
|
||||
// Stream: use UniformResourceIterator.
|
||||
$grav = Grav::instance();
|
||||
/** @var UniformResourceLocator $locator */
|
||||
$locator = $grav['locator'];
|
||||
$iterator = $locator->getIterator($this->search, null);
|
||||
$grav = Grav::instance();
|
||||
|
||||
/** @var UniformResourceLocator $locator */
|
||||
$locator = $grav['locator'];
|
||||
|
||||
// Get stream / directory iterator.
|
||||
if ($locator->isStream($this->search)) {
|
||||
$iterator = $locator->getIterator($this->search);
|
||||
} else {
|
||||
// Not a stream: use DirectoryIterator.
|
||||
$iterator = new \DirectoryIterator($this->search);
|
||||
}
|
||||
|
||||
@@ -138,6 +71,27 @@ class Blueprints
|
||||
$this->types[$name] = ucfirst(strtr($name, '_', ' '));
|
||||
}
|
||||
}
|
||||
|
||||
return $this->types;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Load blueprint file.
|
||||
*
|
||||
* @param string $name Name of the blueprint.
|
||||
* @return Blueprint
|
||||
*/
|
||||
protected function loadFile($name)
|
||||
{
|
||||
$blueprint = new Blueprint($name);
|
||||
|
||||
if (is_array($this->search) || is_object($this->search)) {
|
||||
$blueprint->setOverrides($this->search);
|
||||
} else {
|
||||
$blueprint->setContext($this->search);
|
||||
}
|
||||
|
||||
return $blueprint->load()->init();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,7 +5,6 @@ use RocketTheme\Toolbox\ArrayTraits\Countable;
|
||||
use RocketTheme\Toolbox\ArrayTraits\Export;
|
||||
use RocketTheme\Toolbox\ArrayTraits\ExportInterface;
|
||||
use RocketTheme\Toolbox\ArrayTraits\NestedArrayAccessWithGetters;
|
||||
use RocketTheme\Toolbox\Blueprints\Blueprints;
|
||||
use RocketTheme\Toolbox\File\File;
|
||||
use RocketTheme\Toolbox\File\FileInterface;
|
||||
|
||||
@@ -211,18 +210,18 @@ class Data implements DataInterface, \ArrayAccess, \Countable, ExportInterface
|
||||
*/
|
||||
public function extra()
|
||||
{
|
||||
return $this->blueprints ? $this->blueprints->extra($this->items) : array();
|
||||
return $this->blueprints()->extra($this->items);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return blueprints.
|
||||
*
|
||||
* @return Blueprints
|
||||
* @return Blueprint
|
||||
*/
|
||||
public function blueprints()
|
||||
{
|
||||
if (!$this->blueprints){
|
||||
$this->blueprints = new Blueprints;
|
||||
$this->blueprints = new Blueprint;
|
||||
} elseif (is_callable($this->blueprints)) {
|
||||
// Lazy load blueprints.
|
||||
$blueprints = $this->blueprints;
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
namespace Grav\Common\Data;
|
||||
|
||||
use Grav\Common\Grav;
|
||||
use Grav\Common\GravTrait;
|
||||
use Symfony\Component\Yaml\Exception\ParseException;
|
||||
use Symfony\Component\Yaml\Parser;
|
||||
|
||||
@@ -16,53 +17,63 @@ class Validation
|
||||
/**
|
||||
* Validate value against a blueprint field definition.
|
||||
*
|
||||
* @param mixed $value
|
||||
* @param $value
|
||||
* @param array $field
|
||||
* @throws \RuntimeException
|
||||
* @return array
|
||||
*/
|
||||
public static function validate($value, array $field)
|
||||
{
|
||||
$validate = isset($field['validate']) ? (array) $field['validate'] : array();
|
||||
$messages = [];
|
||||
|
||||
$validate = isset($field['validate']) ? (array) $field['validate'] : [];
|
||||
|
||||
// If value isn't required, we will stop validation if empty value is given.
|
||||
if (empty($validate['required']) && ($value === null || $value === '')) {
|
||||
return;
|
||||
return $messages;
|
||||
}
|
||||
|
||||
// special case for files, value is never empty and errors with code 4 instead
|
||||
if (empty($validate['required']) && $field['type'] == 'file' && (isset($value['error']) && ($value['error'] == UPLOAD_ERR_NO_FILE || in_array(UPLOAD_ERR_NO_FILE, $value['error'])))) {
|
||||
return;
|
||||
// Special case for files, value is never empty and errors with code 4 instead.
|
||||
if (empty($validate['required']) && $field['type'] == 'file' && isset($value['error'])
|
||||
&& ($value['error'] == UPLOAD_ERR_NO_FILE || in_array(UPLOAD_ERR_NO_FILE, $value['error']))) {
|
||||
return $messages;
|
||||
}
|
||||
|
||||
// Get language class
|
||||
// Get language class.
|
||||
$language = Grav::instance()['language'];
|
||||
|
||||
// Validate type with fallback type text.
|
||||
$type = (string) isset($field['validate']['type']) ? $field['validate']['type'] : $field['type'];
|
||||
$method = 'type'.strtr($type, '-', '_');
|
||||
|
||||
if (!method_exists(__CLASS__, $method)) {
|
||||
$method = 'typeText';
|
||||
}
|
||||
|
||||
$name = ucfirst(isset($field['label']) ? $field['label'] : $field['name']);
|
||||
$message = (string) isset($field['validate']['message']) ? $language->translate($field['validate']['message']) : $language->translate('FORM.INVALID_INPUT', null, true) . ' "' . $language->translate($name) . '"';
|
||||
$message = (string) isset($field['validate']['message'])
|
||||
? $language->translate($field['validate']['message'])
|
||||
: $language->translate('FORM.INVALID_INPUT', null, true) . ' "' . $language->translate($name) . '"';
|
||||
|
||||
$success = self::$method($value, $validate, $field);
|
||||
|
||||
if (method_exists(__CLASS__, $method)) {
|
||||
$success = self::$method($value, $validate, $field);
|
||||
} else {
|
||||
$success = self::typeText($value, $validate, $field);
|
||||
}
|
||||
if (!$success) {
|
||||
throw new \RuntimeException($message);
|
||||
$messages[$field['name']][] = $message;
|
||||
}
|
||||
|
||||
// Check individual rules
|
||||
// Check individual rules.
|
||||
foreach ($validate as $rule => $params) {
|
||||
$method = 'validate'.strtr($rule, '-', '_');
|
||||
$method = 'validate' . ucfirst(strtr($rule, '-', '_'));
|
||||
|
||||
if (method_exists(__CLASS__, $method)) {
|
||||
$success = self::$method($value, $params);
|
||||
|
||||
if (!$success) {
|
||||
throw new \RuntimeException($message);
|
||||
$messages[$field['name']][] = $message;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $messages;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -74,22 +85,24 @@ class Validation
|
||||
*/
|
||||
public static function filter($value, array $field)
|
||||
{
|
||||
$validate = isset($field['validate']) ? (array) $field['validate'] : array();
|
||||
$validate = isset($field['validate']) ? (array) $field['validate'] : [];
|
||||
|
||||
// If value isn't required, we will return null if empty value is given.
|
||||
if (empty($validate['required']) && ($value === null || $value === '')) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// special case for files, value is never empty and errors with code 4 instead
|
||||
if (empty($validate['required']) && $field['type'] == 'file' && (isset($value['error']) && ($value['error'] == UPLOAD_ERR_NO_FILE || in_array(UPLOAD_ERR_NO_FILE, $value['error'])))) {
|
||||
// Special case for files, value is never empty and errors with code 4 instead.
|
||||
if (empty($validate['required']) && $field['type'] == 'file' && isset($value['error'])
|
||||
&& ($value['error'] == UPLOAD_ERR_NO_FILE || in_array(UPLOAD_ERR_NO_FILE, $value['error']))) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// if this is a YAML field, simply parse it and return the value
|
||||
// If this is a YAML field, simply parse it and return the value.
|
||||
if (isset($field['yaml']) && $field['yaml'] === true) {
|
||||
try {
|
||||
$yaml = new Parser();
|
||||
|
||||
return $yaml->parse($value);
|
||||
} catch (ParseException $e) {
|
||||
throw new \RuntimeException($e->getMessage());
|
||||
@@ -98,14 +111,13 @@ class Validation
|
||||
|
||||
// Validate type with fallback type text.
|
||||
$type = (string) isset($field['validate']['type']) ? $field['validate']['type'] : $field['type'];
|
||||
$method = 'filter'.strtr($type, '-', '_');
|
||||
if (method_exists(__CLASS__, $method)) {
|
||||
$value = self::$method($value, $validate, $field);
|
||||
} else {
|
||||
$value = self::filterText($value, $validate, $field);
|
||||
$method = 'filter' . ucfirst(strtr($type, '-', '_'));
|
||||
|
||||
if (!method_exists(__CLASS__, $method)) {
|
||||
$method = 'filterText';
|
||||
}
|
||||
|
||||
return $value;
|
||||
return self::$method($value, $validate, $field);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -627,11 +639,11 @@ class Validation
|
||||
|
||||
public static function validateRequired($value, $params)
|
||||
{
|
||||
if (is_string($value)) {
|
||||
$value = trim($value);
|
||||
if (is_scalar($value)) {
|
||||
return (bool) $params !== true || $value !== '';
|
||||
} else {
|
||||
return (bool) $params !== true || !empty($value);
|
||||
}
|
||||
|
||||
return (bool) $params !== true || !empty($value);
|
||||
}
|
||||
|
||||
public static function validatePattern($value, $params)
|
||||
@@ -699,13 +711,14 @@ class Validation
|
||||
|
||||
public static function validateArray($value, $params)
|
||||
{
|
||||
return is_array($value) || ($value instanceof \ArrayAccess
|
||||
return is_array($value)
|
||||
|| ($value instanceof \ArrayAccess
|
||||
&& $value instanceof \Traversable
|
||||
&& $value instanceof \Countable);
|
||||
}
|
||||
|
||||
public static function validateJson($value, $params)
|
||||
{
|
||||
return (bool) (json_decode($value));
|
||||
return (bool) (@json_decode($value));
|
||||
}
|
||||
}
|
||||
|
||||
30
system/src/Grav/Common/Data/ValidationException.php
Normal file
30
system/src/Grav/Common/Data/ValidationException.php
Normal file
@@ -0,0 +1,30 @@
|
||||
<?php
|
||||
namespace Grav\Common\Data;
|
||||
|
||||
use Grav\Common\Grav;
|
||||
|
||||
class ValidationException extends \RuntimeException
|
||||
{
|
||||
protected $messages = [];
|
||||
|
||||
public function setMessages(array $messages = []) {
|
||||
$this->messages = $messages;
|
||||
|
||||
$language = Grav::instance()['language'];
|
||||
$this->message = $language->translate('FORM.VALIDATION_FAIL', null, true) . ' ' . $this->message;
|
||||
|
||||
foreach ($messages as $variable => &$list) {
|
||||
$list = array_unique($list);
|
||||
foreach ($list as $message) {
|
||||
$this->message .= "<br/>$message";
|
||||
}
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getMessages()
|
||||
{
|
||||
return $this->messages;
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,9 @@
|
||||
<?php
|
||||
namespace Grav\Common\Filesystem;
|
||||
|
||||
use Grav\Common\Grav;
|
||||
use RocketTheme\Toolbox\ResourceLocator\UniformResourceLocator;
|
||||
|
||||
/**
|
||||
* Folder helper class.
|
||||
*
|
||||
@@ -19,7 +22,14 @@ abstract class Folder
|
||||
{
|
||||
$last_modified = 0;
|
||||
|
||||
$directory = new \RecursiveDirectoryIterator($path, \RecursiveDirectoryIterator::SKIP_DOTS);
|
||||
/** @var UniformResourceLocator $locator */
|
||||
$locator = Grav::instance()['locator'];
|
||||
$flags = \RecursiveDirectoryIterator::SKIP_DOTS;
|
||||
if ($locator->isStream($path)) {
|
||||
$directory = $locator->getRecursiveIterator($path, $flags);
|
||||
} else {
|
||||
$directory = new \RecursiveDirectoryIterator($path, $flags);
|
||||
}
|
||||
$filter = new RecursiveFolderFilterIterator($directory);
|
||||
$iterator = new \RecursiveIteratorIterator($filter, \RecursiveIteratorIterator::SELF_FIRST);
|
||||
|
||||
@@ -46,7 +56,14 @@ abstract class Folder
|
||||
{
|
||||
$last_modified = 0;
|
||||
|
||||
$directory = new \RecursiveDirectoryIterator($path, \RecursiveDirectoryIterator::SKIP_DOTS);
|
||||
/** @var UniformResourceLocator $locator */
|
||||
$locator = Grav::instance()['locator'];
|
||||
$flags = \RecursiveDirectoryIterator::SKIP_DOTS;
|
||||
if ($locator->isStream($path)) {
|
||||
$directory = $locator->getRecursiveIterator($path, $flags);
|
||||
} else {
|
||||
$directory = new \RecursiveDirectoryIterator($path, $flags);
|
||||
}
|
||||
$recursive = new \RecursiveIteratorIterator($directory, \RecursiveIteratorIterator::SELF_FIRST);
|
||||
$iterator = new \RegexIterator($recursive, '/^.+\.'.$extensions.'$/i');
|
||||
|
||||
@@ -145,7 +162,7 @@ abstract class Folder
|
||||
public static function all($path, array $params = [])
|
||||
{
|
||||
if ($path === false) {
|
||||
throw new \RuntimeException("Path to {$path} doesn't exist.");
|
||||
throw new \RuntimeException("Path doesn't exist.");
|
||||
}
|
||||
|
||||
$compare = isset($params['compare']) ? 'get' . $params['compare'] : null;
|
||||
@@ -158,13 +175,23 @@ abstract class Folder
|
||||
$folders = isset($params['folders']) ? $params['folders'] : true;
|
||||
$files = isset($params['files']) ? $params['files'] : true;
|
||||
|
||||
/** @var UniformResourceLocator $locator */
|
||||
$locator = Grav::instance()['locator'];
|
||||
if ($recursive) {
|
||||
$directory = new \RecursiveDirectoryIterator($path,
|
||||
\RecursiveDirectoryIterator::SKIP_DOTS + \FilesystemIterator::UNIX_PATHS + \FilesystemIterator::CURRENT_AS_SELF);
|
||||
$flags = \RecursiveDirectoryIterator::SKIP_DOTS + \FilesystemIterator::UNIX_PATHS + \FilesystemIterator::CURRENT_AS_SELF;
|
||||
if ($locator->isStream($path)) {
|
||||
$directory = $locator->getRecursiveIterator($path, $flags);
|
||||
} else {
|
||||
$directory = new \RecursiveDirectoryIterator($path, $flags);
|
||||
}
|
||||
$iterator = new \RecursiveIteratorIterator($directory, \RecursiveIteratorIterator::SELF_FIRST);
|
||||
$iterator->setMaxDepth(max($levels, -1));
|
||||
} else {
|
||||
$iterator = new \FilesystemIterator($path);
|
||||
if ($locator->isStream($path)) {
|
||||
$iterator = $locator->getIterator($path);
|
||||
} else {
|
||||
$iterator = new \FilesystemIterator($path);
|
||||
}
|
||||
}
|
||||
|
||||
$results = [];
|
||||
|
||||
@@ -201,7 +201,7 @@ class GPM extends Iterator
|
||||
*
|
||||
* @param $package_name
|
||||
*
|
||||
* @return string
|
||||
* @return string|null
|
||||
*/
|
||||
public function getLatestVersionOfPackage($package_name)
|
||||
{
|
||||
@@ -216,6 +216,8 @@ class GPM extends Iterator
|
||||
if (isset($repository[$package_name])) {
|
||||
return $repository[$package_name]->version;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -223,6 +223,8 @@ class Grav extends Container
|
||||
|
||||
// Initialize configuration.
|
||||
$debugger->startTimer('_config', 'Configuration');
|
||||
/** @var Plugins $plugins */
|
||||
$plugins = $this['plugins']->setup();
|
||||
$this['config']->init();
|
||||
$debugger->stopTimer('_config');
|
||||
|
||||
@@ -262,7 +264,7 @@ class Grav extends Container
|
||||
$debugger->stopTimer('init');
|
||||
|
||||
$debugger->startTimer('plugins', 'Plugins');
|
||||
$this['plugins']->init();
|
||||
$plugins->init();
|
||||
$this->fireEvent('onPluginsInitialized');
|
||||
$debugger->stopTimer('plugins');
|
||||
|
||||
|
||||
@@ -5,6 +5,7 @@ namespace Grav\Common;
|
||||
* Class GravTrait
|
||||
*
|
||||
* @package Grav\Common
|
||||
* @deprecated
|
||||
*/
|
||||
trait GravTrait
|
||||
{
|
||||
|
||||
@@ -87,7 +87,7 @@ class Media extends Getters
|
||||
$medium = MediumFactory::scaledFromMedium($altMedium, $ratio, 1)['file'];
|
||||
}
|
||||
|
||||
if (!$medium) {
|
||||
if (empty($medium)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
@@ -59,12 +59,9 @@ class MediumFactory
|
||||
|
||||
$locator = Grav::instance()['locator'];
|
||||
|
||||
$lookup = $locator->findResources('image://');
|
||||
foreach ($lookup as $lookupPath) {
|
||||
if (is_file($lookupPath . '/' . $params['thumb'])) {
|
||||
$params['thumbnails']['default'] = $lookupPath . '/' . $params['thumb'];
|
||||
break;
|
||||
}
|
||||
$file = $locator->findResource("image://{$params['thumb']}");
|
||||
if ($file) {
|
||||
$params['thumbnails']['default'] = $file;
|
||||
}
|
||||
|
||||
return static::fromArray($params);
|
||||
|
||||
@@ -100,8 +100,6 @@ class Page
|
||||
|
||||
/**
|
||||
* Page Object Constructor
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
@@ -111,8 +109,6 @@ class Page
|
||||
$this->taxonomy = [];
|
||||
$this->process = $config->get('system.pages.process');
|
||||
$this->published = true;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -883,12 +879,14 @@ class Page
|
||||
*/
|
||||
public function blueprints()
|
||||
{
|
||||
$grav = Grav::instance();
|
||||
|
||||
/** @var Pages $pages */
|
||||
$pages = Grav::instance()['pages'];
|
||||
$pages = $grav['pages'];
|
||||
|
||||
$blueprint = $pages->blueprints($this->blueprintName());
|
||||
$fields = $blueprint->fields();
|
||||
$edit_mode = isset(Grav::instance()['admin']) ? Grav::instance()['config']->get('plugins.admin.edit_mode') : null;
|
||||
$edit_mode = isset($grav['admin']) ? $grav['config']->get('plugins.admin.edit_mode') : null;
|
||||
|
||||
// override if you only want 'normal' mode
|
||||
if (empty($fields) && ($edit_mode == 'auto' || $edit_mode == 'normal')) {
|
||||
@@ -1419,17 +1417,19 @@ class Page
|
||||
*/
|
||||
public function url($include_host = false, $canonical = false, $include_lang = true)
|
||||
{
|
||||
$grav = Grav::instance();
|
||||
|
||||
/** @var Pages $pages */
|
||||
$pages = Grav::instance()['pages'];
|
||||
$pages = $grav['pages'];
|
||||
|
||||
/** @var Config $config */
|
||||
$config = Grav::instance()['config'];
|
||||
$config = $grav['config'];
|
||||
|
||||
/** @var Language $language */
|
||||
$language = Grav::instance()['language'];
|
||||
$language = $grav['language'];
|
||||
|
||||
/** @var Uri $uri */
|
||||
$uri = Grav::instance()['uri'];
|
||||
$uri = $grav['uri'];
|
||||
|
||||
// get pre-route
|
||||
if ($include_lang && $language->enabled()) {
|
||||
|
||||
@@ -391,7 +391,7 @@ class Pages
|
||||
$blueprint = $this->blueprints->get('default');
|
||||
}
|
||||
|
||||
if (!$blueprint->initialized) {
|
||||
if (empty($blueprint->initialized)) {
|
||||
$this->grav->fireEvent('onBlueprintCreated', new Event(['blueprint' => $blueprint]));
|
||||
$blueprint->initialized = true;
|
||||
}
|
||||
@@ -470,11 +470,10 @@ class Pages
|
||||
*/
|
||||
public static function getTypes()
|
||||
{
|
||||
$locator = Grav::instance()['locator'];
|
||||
if (!self::$types) {
|
||||
self::$types = new Types();
|
||||
file_exists('theme://blueprints/') && self::$types->scanBlueprints($locator->findResources('theme://blueprints/'));
|
||||
file_exists('theme://templates/') && self::$types->scanTemplates($locator->findResources('theme://templates/'));
|
||||
self::$types->scanBlueprints('theme://blueprints/');
|
||||
self::$types->scanTemplates('theme://templates/');
|
||||
|
||||
$event = new Event();
|
||||
$event->types = self::$types;
|
||||
@@ -683,6 +682,7 @@ class Pages
|
||||
|
||||
/** @var UniformResourceLocator $locator */
|
||||
$locator = $this->grav['locator'];
|
||||
|
||||
$pages_dir = $locator->findResource('page://');
|
||||
|
||||
if ($config->get('system.cache.enabled')) {
|
||||
@@ -826,8 +826,10 @@ class Pages
|
||||
// set current modified of page
|
||||
$last_modified = $page->modified();
|
||||
|
||||
$iterator = new \FilesystemIterator($directory);
|
||||
|
||||
/** @var \DirectoryIterator $file */
|
||||
foreach (new \FilesystemIterator($directory) as $file) {
|
||||
foreach ($iterator as $file) {
|
||||
$name = $file->getFilename();
|
||||
|
||||
// Ignore all hidden files if set.
|
||||
|
||||
@@ -28,13 +28,21 @@ class Types implements \ArrayAccess, \Iterator, \Countable
|
||||
}
|
||||
}
|
||||
|
||||
public function scanBlueprints($paths)
|
||||
public function scanBlueprints($uri)
|
||||
{
|
||||
$this->items = $this->findBlueprints($paths) + $this->items;
|
||||
if (!is_string($uri)) {
|
||||
throw new \InvalidArgumentException('First parameter must be URI');
|
||||
}
|
||||
|
||||
$this->items = $this->findBlueprints($uri) + $this->items;
|
||||
}
|
||||
|
||||
public function scanTemplates($paths)
|
||||
public function scanTemplates($uri)
|
||||
{
|
||||
if (!is_string($uri)) {
|
||||
throw new \InvalidArgumentException('First parameter must be URI');
|
||||
}
|
||||
|
||||
$options = [
|
||||
'compare' => 'Filename',
|
||||
'pattern' => '|\.html\.twig$|',
|
||||
@@ -52,16 +60,13 @@ class Types implements \ArrayAccess, \Iterator, \Countable
|
||||
// register default by default
|
||||
$this->register('default');
|
||||
|
||||
foreach ((array) $paths as $path) {
|
||||
foreach (Folder::all($path, $options) as $type) {
|
||||
$this->register($type);
|
||||
}
|
||||
$modular_path = rtrim($path, '/') . '/modular';
|
||||
if (file_exists($modular_path)) {
|
||||
foreach (Folder::all($modular_path, $options) as $type) {
|
||||
$this->register('modular/' . $type);
|
||||
}
|
||||
}
|
||||
foreach (Folder::all($uri, $options) as $type) {
|
||||
$this->register($type);
|
||||
}
|
||||
|
||||
$modular_uri = rtrim($uri, '/') . '/modular';
|
||||
foreach (Folder::all($modular_uri, $options) as $type) {
|
||||
$this->register('modular/' . $type);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -91,7 +96,7 @@ class Types implements \ArrayAccess, \Iterator, \Countable
|
||||
return $list;
|
||||
}
|
||||
|
||||
private function findBlueprints($paths)
|
||||
private function findBlueprints($uri)
|
||||
{
|
||||
$options = [
|
||||
'compare' => 'Filename',
|
||||
@@ -103,10 +108,7 @@ class Types implements \ArrayAccess, \Iterator, \Countable
|
||||
'value' => 'PathName',
|
||||
];
|
||||
|
||||
$list = [];
|
||||
foreach ((array) $paths as $path) {
|
||||
$list += Folder::all($path, $options);
|
||||
}
|
||||
$list = Folder::all($uri, $options);
|
||||
|
||||
return $list;
|
||||
}
|
||||
|
||||
@@ -16,6 +16,16 @@ use RocketTheme\Toolbox\File\YamlFile;
|
||||
*/
|
||||
class Plugin implements EventSubscriberInterface
|
||||
{
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
public $name;
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
public $features = [];
|
||||
|
||||
/**
|
||||
* @var Grav
|
||||
*/
|
||||
@@ -27,10 +37,6 @@ class Plugin implements EventSubscriberInterface
|
||||
protected $config;
|
||||
|
||||
protected $active = true;
|
||||
/**
|
||||
* @var \Grav\Common\string
|
||||
*/
|
||||
protected $name;
|
||||
|
||||
/**
|
||||
* By default assign all methods as listeners using the default priority.
|
||||
@@ -58,13 +64,29 @@ class Plugin implements EventSubscriberInterface
|
||||
* @param Grav $grav
|
||||
* @param Config $config
|
||||
*/
|
||||
public function __construct($name, Grav $grav, Config $config)
|
||||
public function __construct($name, Grav $grav, Config $config = null)
|
||||
{
|
||||
$this->grav = $grav;
|
||||
$this->config = $config;
|
||||
$this->name = $name;
|
||||
$this->grav = $grav;
|
||||
if ($config) {
|
||||
$this->setConfig($config);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Config $config
|
||||
* @return $this
|
||||
*/
|
||||
public function setConfig(Config $config)
|
||||
{
|
||||
$this->config = $config;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
*/
|
||||
public function isAdmin()
|
||||
{
|
||||
if (isset($this->grav['admin'])) {
|
||||
@@ -200,10 +222,11 @@ class Plugin implements EventSubscriberInterface
|
||||
return false;
|
||||
}
|
||||
|
||||
$locator = Grav::instance()['locator'];
|
||||
$grav = Grav::instance();
|
||||
$locator = $grav['locator'];
|
||||
$filename = 'config://plugins/' . $plugin_name . '.yaml';
|
||||
$file = YamlFile::instance($locator->findResource($filename, true, true));
|
||||
$content = Grav::instance()['config']->get('plugins.' . $plugin_name);
|
||||
$content = $grav['config']->get('plugins.' . $plugin_name);
|
||||
$file->save($content);
|
||||
$file->free();
|
||||
|
||||
|
||||
@@ -1,13 +1,12 @@
|
||||
<?php
|
||||
namespace Grav\Common;
|
||||
|
||||
use Grav\Common\Grav;
|
||||
use Grav\Common\Config\Config;
|
||||
use Grav\Common\Data\Blueprints;
|
||||
use Grav\Common\Data\Data;
|
||||
use Grav\Common\File\CompiledYamlFile;
|
||||
use RocketTheme\Toolbox\Event\EventDispatcher;
|
||||
use RocketTheme\Toolbox\Event\EventSubscriberInterface;
|
||||
use RocketTheme\Toolbox\ResourceLocator\UniformResourceLocator;
|
||||
|
||||
/**
|
||||
* The Plugins object holds an array of all the plugin objects that
|
||||
@@ -18,58 +17,90 @@ use RocketTheme\Toolbox\Event\EventSubscriberInterface;
|
||||
*/
|
||||
class Plugins extends Iterator
|
||||
{
|
||||
public $formFieldTypes;
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
parent::__construct();
|
||||
|
||||
/** @var UniformResourceLocator $locator */
|
||||
$locator = Grav::instance()['locator'];
|
||||
|
||||
$iterator = $locator->getIterator('plugins://');
|
||||
foreach ($iterator as $directory) {
|
||||
if (!$directory->isDir()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$plugin = $directory->getBasename();
|
||||
|
||||
$this->add($this->loadPlugin($plugin));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Recurses through the plugins directory creating Plugin objects for each plugin it finds.
|
||||
* @return $this
|
||||
*/
|
||||
public function setup()
|
||||
{
|
||||
$blueprints = [];
|
||||
$formFields = [];
|
||||
|
||||
/** @var Plugin $plugin */
|
||||
foreach ($this->items as $plugin) {
|
||||
if (isset($plugin->features['blueprints'])) {
|
||||
$blueprints["plugin://{$plugin->name}/blueprints"] = $plugin->features['blueprints'];
|
||||
}
|
||||
if (method_exists($plugin, 'getFormFieldTypes')) {
|
||||
$formFields[get_class($plugin)] = isset($plugin->features['formfields']) ? $plugin->features['formfields'] : 0;
|
||||
}
|
||||
}
|
||||
|
||||
if ($blueprints) {
|
||||
// Order by priority.
|
||||
arsort($blueprints);
|
||||
|
||||
/** @var UniformResourceLocator $locator */
|
||||
$locator = Grav::instance()['locator'];
|
||||
$locator->addPath('blueprints', '', array_keys($blueprints), 'system/blueprints');
|
||||
}
|
||||
|
||||
if ($formFields) {
|
||||
// Order by priority.
|
||||
arsort($formFields);
|
||||
|
||||
$list = [];
|
||||
foreach ($formFields as $className => $priority) {
|
||||
$plugin = $this->items[$className];
|
||||
$list += $plugin->getFormFieldTypes();
|
||||
}
|
||||
|
||||
$this->formFieldTypes = $list;
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers all plugins.
|
||||
*
|
||||
* @return array|Plugin[] array of Plugin objects
|
||||
* @throws \RuntimeException
|
||||
*/
|
||||
public function init()
|
||||
{
|
||||
/** @var Config $config */
|
||||
$config = Grav::instance()['config'];
|
||||
$plugins = (array)$config->get('plugins');
|
||||
$grav = Grav::instance();
|
||||
|
||||
$inflector = Grav::instance()['inflector'];
|
||||
/** @var Config $config */
|
||||
$config = $grav['config'];
|
||||
|
||||
/** @var EventDispatcher $events */
|
||||
$events = Grav::instance()['events'];
|
||||
$events = $grav['events'];
|
||||
|
||||
foreach ($plugins as $plugin => $data) {
|
||||
if (empty($data['enabled'])) {
|
||||
// Only load enabled plugins.
|
||||
continue;
|
||||
}
|
||||
|
||||
$locator = Grav::instance()['locator'];
|
||||
$filePath = $locator->findResource('plugins://' . $plugin . DS . $plugin . PLUGIN_EXT);
|
||||
if (!is_file($filePath)) {
|
||||
Grav::instance()['log']->addWarning(sprintf("Plugin '%s' enabled but not found! Try clearing cache with `bin/grav clear-cache`", $plugin));
|
||||
continue;
|
||||
}
|
||||
|
||||
require_once $filePath;
|
||||
|
||||
$pluginClassFormat = [
|
||||
'Grav\\Plugin\\' . ucfirst($plugin) . 'Plugin',
|
||||
'Grav\\Plugin\\' . $inflector->camelize($plugin) . 'Plugin'
|
||||
];
|
||||
$pluginClassName = false;
|
||||
|
||||
foreach ($pluginClassFormat as $pluginClass) {
|
||||
if (class_exists($pluginClass)) {
|
||||
$pluginClassName = $pluginClass;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (false === $pluginClassName) {
|
||||
throw new \RuntimeException(sprintf("Plugin '%s' class not found! Try reinstalling this plugin.",
|
||||
$plugin));
|
||||
}
|
||||
|
||||
$instance = new $pluginClassName($plugin, Grav::instance(), $config);
|
||||
if ($instance instanceof EventSubscriberInterface) {
|
||||
foreach ($this->items as $instance) {
|
||||
// Register only enabled plugins.
|
||||
if ($config["plugins.{$instance->name}.enabled"] && $instance instanceof Plugin) {
|
||||
$instance->setConfig($config);
|
||||
$events->addSubscriber($instance);
|
||||
}
|
||||
}
|
||||
@@ -96,28 +127,17 @@ class Plugins extends Iterator
|
||||
*/
|
||||
public static function all()
|
||||
{
|
||||
$plugins = Grav::instance()['plugins'];
|
||||
$list = [];
|
||||
$locator = Grav::instance()['locator'];
|
||||
|
||||
$plugins = (array)$locator->findResources('plugins://', false);
|
||||
foreach ($plugins as $path) {
|
||||
$iterator = new \DirectoryIterator($path);
|
||||
foreach ($plugins as $instance) {
|
||||
$name = $instance->name;
|
||||
$result = self::get($name);
|
||||
|
||||
/** @var \DirectoryIterator $directory */
|
||||
foreach ($iterator as $directory) {
|
||||
if (!$directory->isDir() || $directory->isDot()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$plugin = $directory->getBasename();
|
||||
$result = self::get($plugin);
|
||||
|
||||
if ($result) {
|
||||
$list[$plugin] = $result;
|
||||
}
|
||||
if ($result) {
|
||||
$list[$name] = $result;
|
||||
}
|
||||
}
|
||||
ksort($list);
|
||||
|
||||
return $list;
|
||||
}
|
||||
@@ -133,7 +153,6 @@ class Plugins extends Iterator
|
||||
{
|
||||
$blueprints = new Blueprints('plugins://');
|
||||
$blueprint = $blueprints->get("{$name}/blueprints");
|
||||
$blueprint->name = $name;
|
||||
|
||||
// Load default configuration.
|
||||
$file = CompiledYamlFile::instance("plugins://{$name}/{$name}" . YAML_EXT);
|
||||
@@ -155,4 +174,29 @@ class Plugins extends Iterator
|
||||
return $obj;
|
||||
}
|
||||
|
||||
protected function loadPlugin($name)
|
||||
{
|
||||
$grav = Grav::instance();
|
||||
$locator = $grav['locator'];
|
||||
|
||||
$filePath = $locator->findResource('plugins://' . $name . DS . $name . PLUGIN_EXT);
|
||||
if (!is_file($filePath)) {
|
||||
$grav['log']->addWarning(
|
||||
sprintf("Plugin '%s' enabled but not found! Try clearing cache with `bin/grav clear-cache`", $name)
|
||||
);
|
||||
return null;
|
||||
}
|
||||
|
||||
require_once $filePath;
|
||||
|
||||
$pluginClassName = 'Grav\\Plugin\\' . ucfirst($name) . 'Plugin';
|
||||
if (!class_exists($pluginClassName)) {
|
||||
$pluginClassName = 'Grav\\Plugin\\' . $grav['inflector']->camelize($name) . 'Plugin';
|
||||
if (!class_exists($pluginClassName)) {
|
||||
throw new \RuntimeException(sprintf("Plugin '%s' class not found! Try reinstalling this plugin.", $name));
|
||||
}
|
||||
}
|
||||
return new $pluginClassName($name, $grav);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -34,7 +34,7 @@ class StreamsServiceProvider implements ServiceProviderInterface
|
||||
Stream::setLocator($locator);
|
||||
ReadOnlyStream::setLocator($locator);
|
||||
|
||||
return new StreamBuilder($setup->getStreams($c));
|
||||
return new StreamBuilder($setup->getStreams());
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,10 +1,12 @@
|
||||
<?php
|
||||
namespace Grav\Common;
|
||||
|
||||
use RocketTheme\Toolbox\Session\Session as BaseSession;
|
||||
|
||||
/**
|
||||
* Wrapper for Session
|
||||
*/
|
||||
class Session extends \RocketTheme\Toolbox\Session\Session
|
||||
class Session extends BaseSession
|
||||
{
|
||||
protected $grav;
|
||||
protected $session;
|
||||
|
||||
@@ -10,8 +10,6 @@ use RocketTheme\Toolbox\File\YamlFile;
|
||||
*/
|
||||
class Theme extends Plugin
|
||||
{
|
||||
public $name;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
@@ -21,8 +19,6 @@ class Theme extends Plugin
|
||||
*/
|
||||
public function __construct(Grav $grav, Config $config, $name)
|
||||
{
|
||||
$this->name = $name;
|
||||
|
||||
parent::__construct($name, $grav, $config);
|
||||
}
|
||||
|
||||
@@ -39,10 +35,11 @@ class Theme extends Plugin
|
||||
return false;
|
||||
}
|
||||
|
||||
$locator = Grav::instance()['locator'];
|
||||
$grav = Grav::instance();
|
||||
$locator = $grav['locator'];
|
||||
$filename = 'config://themes/' . $theme_name . '.yaml';
|
||||
$file = YamlFile::instance($locator->findResource($filename, true, true));
|
||||
$content = Grav::instance()['config']->get('themes.' . $theme_name);
|
||||
$content = $grav['config']->get('themes.' . $theme_name);
|
||||
$file->save($content);
|
||||
$file->free();
|
||||
|
||||
|
||||
@@ -79,24 +79,23 @@ class Themes extends Iterator
|
||||
public function all()
|
||||
{
|
||||
$list = [];
|
||||
$locator = Grav::instance()['locator'];
|
||||
|
||||
$themes = (array)$locator->findResources('themes://', false);
|
||||
foreach ($themes as $path) {
|
||||
$iterator = new \DirectoryIterator($path);
|
||||
/** @var UniformResourceLocator $locator */
|
||||
$locator = $this->grav['locator'];
|
||||
|
||||
/** @var \DirectoryIterator $directory */
|
||||
foreach ($iterator as $directory) {
|
||||
if (!$directory->isDir() || $directory->isDot()) {
|
||||
continue;
|
||||
}
|
||||
$iterator = $locator->getIterator('themes://');
|
||||
|
||||
$theme = $directory->getBasename();
|
||||
$result = self::get($theme);
|
||||
/** @var \DirectoryIterator $directory */
|
||||
foreach ($iterator as $directory) {
|
||||
if (!$directory->isDir() || $directory->isDot()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if ($result) {
|
||||
$list[$theme] = $result;
|
||||
}
|
||||
$theme = $directory->getBasename();
|
||||
$result = self::get($theme);
|
||||
|
||||
if ($result) {
|
||||
$list[$theme] = $result;
|
||||
}
|
||||
}
|
||||
ksort($list);
|
||||
@@ -120,7 +119,6 @@ class Themes extends Iterator
|
||||
|
||||
$blueprints = new Blueprints('themes://');
|
||||
$blueprint = $blueprints->get("{$name}/blueprints");
|
||||
$blueprint->name = $name;
|
||||
|
||||
// Load default configuration.
|
||||
$file = CompiledYamlFile::instance("themes://{$name}/{$name}" . YAML_EXT);
|
||||
@@ -141,7 +139,7 @@ class Themes extends Iterator
|
||||
$obj = new Data($file->content(), $blueprint);
|
||||
|
||||
// Override with user configuration.
|
||||
$obj->merge($this->grav['config']->get('themes.' . $name) ?: []);
|
||||
$obj->merge($this->config->get('themes.' . $name) ?: []);
|
||||
|
||||
// Save configuration always to user/config.
|
||||
$file = CompiledYamlFile::instance("config://themes/{$name}" . YAML_EXT);
|
||||
|
||||
@@ -325,7 +325,7 @@ class Uri
|
||||
$valid_page_types = implode('|', $config->get('system.pages.types'));
|
||||
|
||||
// Strip the file extension for valid page types
|
||||
if (preg_match("/\.(" . $valid_page_types . ")$/", $parts['basename'])) {
|
||||
if (preg_match('/\.(' . $valid_page_types . ')$/', $parts['basename'])) {
|
||||
$uri = rtrim(str_replace(DIRECTORY_SEPARATOR, DS, $parts['dirname']), DS) . '/' . $parts['filename'];
|
||||
}
|
||||
|
||||
@@ -748,7 +748,7 @@ class Uri
|
||||
* @param Page $page the current page to use as reference
|
||||
* @param string $url the URL as it was written in the markdown
|
||||
* @param string $type the type of URL, image | link
|
||||
* @param null $absolute if null, will use system default, if true will use absolute links internally
|
||||
* @param bool $absolute if null, will use system default, if true will use absolute links internally
|
||||
*
|
||||
* @return string the more friendly formatted url
|
||||
*/
|
||||
@@ -965,7 +965,6 @@ class Uri
|
||||
if ($type == 'link' && $language->enabled()) {
|
||||
$language_append = $language->getLanguageURLPrefix();
|
||||
}
|
||||
|
||||
$pages_dir = $grav['locator']->findResource('page://');
|
||||
if (is_null($relative)) {
|
||||
$base = $grav['base_url'];
|
||||
|
||||
@@ -54,7 +54,7 @@ class Group extends Data
|
||||
$content = [];
|
||||
}
|
||||
|
||||
$blueprints = new Blueprints('blueprints://');
|
||||
$blueprints = new Blueprints;
|
||||
$blueprint = $blueprints->get('user/group');
|
||||
if (!isset($content['groupname'])) {
|
||||
$content['groupname'] = $groupname;
|
||||
@@ -69,18 +69,21 @@ class Group extends Data
|
||||
*/
|
||||
public function save()
|
||||
{
|
||||
$blueprints = new Blueprints('blueprints://');
|
||||
$grav = Grav::instance();
|
||||
$config = $grav['config'];
|
||||
|
||||
$blueprints = new Blueprints;
|
||||
$blueprint = $blueprints->get('user/group');
|
||||
|
||||
$fields = $blueprint->fields();
|
||||
|
||||
Grav::instance()['config']->set("groups.$this->groupname", []);
|
||||
$config->set("groups.$this->groupname", []);
|
||||
|
||||
foreach ($fields as $field) {
|
||||
if ($field['type'] == 'text') {
|
||||
$value = $field['name'];
|
||||
if (isset($this->items[$value])) {
|
||||
Grav::instance()['config']->set("groups.$this->groupname.$value", $this->items[$value]);
|
||||
$config->set("groups.$this->groupname.$value", $this->items[$value]);
|
||||
}
|
||||
}
|
||||
if ($field['type'] == 'array') {
|
||||
@@ -89,7 +92,7 @@ class Group extends Data
|
||||
|
||||
if ($arrayValues) {
|
||||
foreach ($arrayValues as $arrayIndex => $arrayValue) {
|
||||
Grav::instance()['config']->set("groups.$this->groupname.$value.$arrayIndex", $arrayValue);
|
||||
$config->set("groups.$this->groupname.$value.$arrayIndex", $arrayValue);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -97,8 +100,8 @@ class Group extends Data
|
||||
|
||||
$type = 'groups';
|
||||
$blueprints = $this->blueprints("config/{$type}");
|
||||
$obj = new Data(Grav::instance()['config']->get($type), $blueprints);
|
||||
$file = CompiledYamlFile::instance(Grav::instance()['locator']->findResource("config://{$type}.yaml"));
|
||||
$obj = new Data($config->get($type), $blueprints);
|
||||
$file = CompiledYamlFile::instance($grav['locator']->findResource("config://{$type}.yaml"));
|
||||
$obj->file($file);
|
||||
$obj->save();
|
||||
}
|
||||
@@ -112,16 +115,18 @@ class Group extends Data
|
||||
*/
|
||||
public static function remove($groupname)
|
||||
{
|
||||
$blueprints = new Blueprints('blueprints://');
|
||||
$grav = Grav::instance();
|
||||
$config = $grav['config'];
|
||||
$blueprints = new Blueprints;
|
||||
$blueprint = $blueprints->get('user/group');
|
||||
|
||||
$groups = Grav::instance()['config']->get("groups");
|
||||
$groups = $config->get("groups");
|
||||
unset($groups[$groupname]);
|
||||
Grav::instance()['config']->set("groups", $groups);
|
||||
$config->set("groups", $groups);
|
||||
|
||||
$type = 'groups';
|
||||
$obj = new Data(Grav::instance()['config']->get($type), $blueprint);
|
||||
$file = CompiledYamlFile::instance(Grav::instance()['locator']->findResource("config://{$type}.yaml"));
|
||||
$obj = new Data($config->get($type), $blueprint);
|
||||
$file = CompiledYamlFile::instance($grav['locator']->findResource("config://{$type}.yaml"));
|
||||
$obj->file($file);
|
||||
$obj->save();
|
||||
|
||||
|
||||
@@ -34,7 +34,7 @@ class User extends Data
|
||||
// force lowercase of username
|
||||
$username = strtolower($username);
|
||||
|
||||
$blueprints = new Blueprints('blueprints://');
|
||||
$blueprints = new Blueprints;
|
||||
$blueprint = $blueprints->get('user/account');
|
||||
$file_path = $locator->findResource('account://' . $username . YAML_EXT);
|
||||
$file = CompiledYamlFile::instance($file_path);
|
||||
|
||||
Reference in New Issue
Block a user