Merge branches 'develop' and 'feature/blueprints-update' of https://github.com/getgrav/grav into develop

This commit is contained in:
Matias Griese
2016-03-07 14:58:02 +02:00
35 changed files with 828 additions and 2292 deletions

View File

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

File diff suppressed because it is too large Load Diff

View File

@@ -29,7 +29,6 @@ form:
content:
type: markdown
showPreview: true
validate:
type: textarea

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

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

View File

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

View File

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

View File

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

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

View File

@@ -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 = [];

View File

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

View File

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

View File

@@ -5,6 +5,7 @@ namespace Grav\Common;
* Class GravTrait
*
* @package Grav\Common
* @deprecated
*/
trait GravTrait
{

View File

@@ -87,7 +87,7 @@ class Media extends Getters
$medium = MediumFactory::scaledFromMedium($altMedium, $ratio, 1)['file'];
}
if (!$medium) {
if (empty($medium)) {
continue;
}

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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