mirror of
https://github.com/getgrav/grav.git
synced 2026-03-17 01:51:08 +01:00
Merge branch 'release/1.6.7'
This commit is contained in:
13
CHANGELOG.md
13
CHANGELOG.md
@@ -1,3 +1,16 @@
|
||||
# v1.6.7
|
||||
## 04/22/2019
|
||||
|
||||
1. [](#new)
|
||||
* Added a new `bin/grav yamllinter` CLI command to find YAML Linting issues [#2468](https://github.com/getgrav/grav/issues/2468#issuecomment-485151681)
|
||||
1. [](#improved)
|
||||
* Improve `FormTrait` backwards compatibility with existing forms
|
||||
* Added a new `Utils::getSubnet()` function for IPv4/IPv6 parsing [#2465](https://github.com/getgrav/grav/pull/2465)
|
||||
1. [](#bugfix)
|
||||
* Remove disabled fields from the form schema
|
||||
* Fix issue when excluding `inlineJs` and `inlineCss` from Assets pipeline [#2468](https://github.com/getgrav/grav/issues/2468)
|
||||
* Fix for manually set position on external URLs [#2470](https://github.com/getgrav/grav/issues/2470)
|
||||
|
||||
# v1.6.6
|
||||
## 04/17/2019
|
||||
|
||||
|
||||
19
bin/grav
19
bin/grav
@@ -3,6 +3,7 @@
|
||||
|
||||
use Grav\Common\Composer;
|
||||
use Grav\Common\Grav;
|
||||
use League\CLImate\CLImate;
|
||||
use Symfony\Component\Console\Application;
|
||||
|
||||
\define('GRAV_CLI', true);
|
||||
@@ -24,7 +25,22 @@ if (version_compare($ver = PHP_VERSION, $req = GRAV_PHP_MIN, '<')) {
|
||||
exit(sprintf("You are running PHP %s, but Grav needs at least PHP %s to run.\n", $ver, $req));
|
||||
}
|
||||
|
||||
Grav::instance(array('loader' => $autoload));
|
||||
$climate = new League\CLImate\CLImate;
|
||||
$climate->arguments->add([
|
||||
'environment' => [
|
||||
'prefix' => 'e',
|
||||
'longPrefix' => 'env',
|
||||
'description' => 'Configuration Environment',
|
||||
'defaultValue' => 'localhost'
|
||||
]
|
||||
]);
|
||||
$climate->arguments->parse();
|
||||
|
||||
// Set up environment based on params.
|
||||
$environment = $climate->arguments->get('environment');
|
||||
|
||||
$grav = Grav::instance(array('loader' => $autoload));
|
||||
$grav->setup($environment);
|
||||
|
||||
if (!ini_get('date.timezone')) {
|
||||
date_default_timezone_set('UTC');
|
||||
@@ -46,5 +62,6 @@ $app->addCommands(array(
|
||||
new \Grav\Console\Cli\SchedulerCommand(),
|
||||
new \Grav\Console\Cli\SecurityCommand(),
|
||||
new \Grav\Console\Cli\LogViewerCommand(),
|
||||
new \Grav\Console\Cli\YamlLinterCommand(),
|
||||
));
|
||||
$app->run();
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
|
||||
// Some standard defines
|
||||
define('GRAV', true);
|
||||
define('GRAV_VERSION', '1.6.6');
|
||||
define('GRAV_VERSION', '1.6.7');
|
||||
define('GRAV_TESTING', false);
|
||||
define('DS', '/');
|
||||
|
||||
|
||||
@@ -172,7 +172,8 @@ class Assets extends PropertyObject
|
||||
// If pipeline disabled, set to position if provided, else after
|
||||
if (isset($options['pipeline'])) {
|
||||
if ($options['pipeline'] === false) {
|
||||
$excludes = strtolower($type . '_pipeline_before_excludes');
|
||||
$exclude_type = ($type === $this::JS_TYPE || $type === $this::INLINE_JS_TYPE) ? $this::JS_TYPE : $this::CSS_TYPE;
|
||||
$excludes = strtolower($exclude_type . '_pipeline_before_excludes');
|
||||
if ($this->{$excludes}) {
|
||||
$default = 'after';
|
||||
} else {
|
||||
@@ -271,7 +272,7 @@ class Assets extends PropertyObject
|
||||
|
||||
$type = $asset->getType();
|
||||
|
||||
if ($asset->getRemote() && $this->{$type . '_pipeline_include_externals'} === false) {
|
||||
if ($asset->getRemote() && $this->{$type . '_pipeline_include_externals'} === false && $asset['position'] === 'pipeline' ) {
|
||||
if ($this->{$type . '_pipeline_before_excludes'}) {
|
||||
$asset->setPosition('after');
|
||||
} else {
|
||||
@@ -281,6 +282,7 @@ class Assets extends PropertyObject
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if ($asset[$key] === $value) return true;
|
||||
return false;
|
||||
});
|
||||
|
||||
@@ -142,7 +142,7 @@ class BlueprintSchema extends BlueprintSchemaBase implements ExportInterface
|
||||
|
||||
if ($rule) {
|
||||
// Item has been defined in blueprints.
|
||||
if (!empty($rule['validate']['ignore'])) {
|
||||
if (!empty($rule['disabled']) || !empty($rule['validate']['ignore'])) {
|
||||
// Skip validation in the ignored field.
|
||||
continue;
|
||||
}
|
||||
@@ -178,7 +178,7 @@ class BlueprintSchema extends BlueprintSchemaBase implements ExportInterface
|
||||
$val = $rules[$key] ?? $rules['*'] ?? null;
|
||||
$rule = \is_string($val) ? $this->items[$val] : null;
|
||||
|
||||
if (empty($rule['validate']['ignore'])) {
|
||||
if (empty($rule['disabled']) && empty($rule['validate']['ignore'])) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
@@ -191,7 +191,7 @@ class BlueprintSchema extends BlueprintSchemaBase implements ExportInterface
|
||||
|
||||
if ($rule) {
|
||||
// Item has been defined in blueprints.
|
||||
if (!empty($rule['validate']['ignore'])) {
|
||||
if (!empty($rule['disabled']) || !empty($rule['validate']['ignore'])) {
|
||||
// Skip any data in the ignored field.
|
||||
unset($results[$key]);
|
||||
continue;
|
||||
@@ -240,6 +240,8 @@ class BlueprintSchema extends BlueprintSchemaBase implements ExportInterface
|
||||
if (
|
||||
// Not an input field
|
||||
!$field
|
||||
// Field has been disabled
|
||||
|| !empty($field['disabled'])
|
||||
// Field validation is set to be ignored
|
||||
|| !empty($field['validate']['ignore'])
|
||||
// Field is toggleable and the toggle is turned off
|
||||
@@ -273,7 +275,7 @@ class BlueprintSchema extends BlueprintSchemaBase implements ExportInterface
|
||||
$field = $this->items[$field];
|
||||
|
||||
// Skip ignored field, it will not be required.
|
||||
if (!empty($field['validate']['ignore'])) {
|
||||
if (!empty($field['disabled']) || !empty($field['validate']['ignore'])) {
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
76
system/src/Grav/Common/Helpers/YamlLinter.php
Normal file
76
system/src/Grav/Common/Helpers/YamlLinter.php
Normal file
@@ -0,0 +1,76 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @package Grav\Common\Helpers
|
||||
*
|
||||
* @copyright Copyright (C) 2015 - 2019 Trilby Media, LLC. All rights reserved.
|
||||
* @license MIT License; see LICENSE file for details.
|
||||
*/
|
||||
|
||||
namespace Grav\Common\Helpers;
|
||||
|
||||
use Grav\Common\Grav;
|
||||
use RocketTheme\Toolbox\File\MarkdownFile;
|
||||
use RocketTheme\Toolbox\ResourceLocator\UniformResourceLocator;
|
||||
use Symfony\Component\Yaml\Yaml;
|
||||
|
||||
class YamlLinter
|
||||
{
|
||||
public static function lint()
|
||||
{
|
||||
$errors = static::lintConfig();
|
||||
$errors = $errors + static::lintPages();
|
||||
|
||||
return $errors;
|
||||
}
|
||||
|
||||
public static function lintPages()
|
||||
{
|
||||
return static::recurseFolder('page://');
|
||||
}
|
||||
|
||||
public static function lintConfig()
|
||||
{
|
||||
return static::recurseFolder('config://');
|
||||
}
|
||||
|
||||
public static function recurseFolder($path, $extensions = 'md|yaml')
|
||||
{
|
||||
$lint_errors = [];
|
||||
|
||||
/** @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');
|
||||
|
||||
/** @var \RecursiveDirectoryIterator $file */
|
||||
foreach ($iterator as $filepath => $file) {
|
||||
try {
|
||||
Yaml::parse(static::extractYaml($filepath));
|
||||
} catch (\Exception $e) {
|
||||
$lint_errors[str_replace(GRAV_ROOT, '', $filepath)] = $e->getMessage();
|
||||
}
|
||||
}
|
||||
|
||||
return $lint_errors;
|
||||
}
|
||||
|
||||
protected static function extractYaml($path)
|
||||
{
|
||||
$extension = pathinfo($path, PATHINFO_EXTENSION);
|
||||
if ($extension === 'md') {
|
||||
$file = MarkdownFile::instance($path);
|
||||
$contents = $file->frontmatter();
|
||||
} else {
|
||||
$contents = file_get_contents($path);
|
||||
}
|
||||
return $contents;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1469,4 +1469,44 @@ abstract class Utils
|
||||
|
||||
return $string;
|
||||
}
|
||||
|
||||
/**
|
||||
* Find the subnet of an ip with CIDR prefix size
|
||||
*
|
||||
* @param string $ip
|
||||
* @param int $prefix
|
||||
*
|
||||
* @return string
|
||||
* @throws \InvalidArgumentException if provided an invalid IP
|
||||
*/
|
||||
public static function getSubnet($ip, $prefix = 64)
|
||||
{
|
||||
if (!filter_var($ip, FILTER_VALIDATE_IP)) {
|
||||
throw new \InvalidArgumentException('Invalid IP: ' . $ip);
|
||||
}
|
||||
|
||||
// Packed representation of IP
|
||||
$ip = inet_pton($ip);
|
||||
|
||||
// Maximum netmask length = same as packed address
|
||||
$len = 8*strlen($ip);
|
||||
if ($prefix > $len) $prefix = $len;
|
||||
|
||||
$mask = str_repeat('f', $prefix>>2);
|
||||
|
||||
switch($prefix & 3)
|
||||
{
|
||||
case 3: $mask .= 'e'; break;
|
||||
case 2: $mask .= 'c'; break;
|
||||
case 1: $mask .= '8'; break;
|
||||
}
|
||||
$mask = str_pad($mask, $len>>2, '0');
|
||||
|
||||
// Packed representation of netmask
|
||||
$mask = pack('H*', $mask);
|
||||
// Bitwise - Take all bits that are both 1 to generate subnet
|
||||
$subnet = inet_ntop($ip & $mask);
|
||||
|
||||
return $subnet;
|
||||
}
|
||||
}
|
||||
|
||||
73
system/src/Grav/Console/Cli/YamlLinterCommand.php
Normal file
73
system/src/Grav/Console/Cli/YamlLinterCommand.php
Normal file
@@ -0,0 +1,73 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @package Grav\Console\Cli
|
||||
*
|
||||
* @copyright Copyright (C) 2015 - 2019 Trilby Media, LLC. All rights reserved.
|
||||
* @license MIT License; see LICENSE file for details.
|
||||
*/
|
||||
|
||||
namespace Grav\Console\Cli;
|
||||
|
||||
use Grav\Common\Grav;
|
||||
use Grav\Common\Helpers\LogViewer;
|
||||
use Grav\Common\Helpers\YamlLinter;
|
||||
use Grav\Common\Utils;
|
||||
use Grav\Console\ConsoleCommand;
|
||||
use Symfony\Component\Console\Input\InputOption;
|
||||
use Symfony\Component\Console\Style\SymfonyStyle;
|
||||
|
||||
class YamlLinterCommand extends ConsoleCommand
|
||||
{
|
||||
protected function configure()
|
||||
{
|
||||
$this
|
||||
->setName('yamllinter')
|
||||
->addOption(
|
||||
'env',
|
||||
'e',
|
||||
InputOption::VALUE_OPTIONAL,
|
||||
'The environment to trigger a specific configuration. For example: localhost, mysite.dev, www.mysite.com'
|
||||
)
|
||||
->setDescription('Checks various files for YAML errors')
|
||||
->setHelp("Checks various files for YAML errors");
|
||||
}
|
||||
|
||||
protected function serve()
|
||||
{
|
||||
$grav = Grav::instance();
|
||||
$grav->setup();
|
||||
|
||||
$io = new SymfonyStyle($this->input, $this->output);
|
||||
|
||||
$io->title('Yaml Linter');
|
||||
|
||||
$io->section('User Configuration');
|
||||
$errors = YamlLinter::lintConfig();
|
||||
|
||||
if (empty($errors)) {
|
||||
$io->success('No YAML Linting issues with configuration');
|
||||
} else {
|
||||
$this->displayErrors($errors, $io);
|
||||
}
|
||||
|
||||
|
||||
$io->section('Pages Frontmatter');
|
||||
$errors = YamlLinter::lintPages();
|
||||
|
||||
if (empty($errors)) {
|
||||
$io->success('No YAML Linting issues with pages');
|
||||
} else {
|
||||
$this->displayErrors($errors, $io);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
protected function displayErrors($errors, $io)
|
||||
{
|
||||
$io->error("YAML Linting issues found...");
|
||||
foreach ($errors as $path => $error) {
|
||||
$io->writeln("<yellow>$path</yellow> - $error");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -27,11 +27,7 @@ class MemoryCache extends AbstractCache
|
||||
|
||||
public function doGet($key, $miss)
|
||||
{
|
||||
if (!array_key_exists($key, $this->cache)) {
|
||||
return $miss;
|
||||
}
|
||||
|
||||
return $this->cache[$key];
|
||||
return $this->cache[$key] ?? $miss;
|
||||
}
|
||||
|
||||
public function doSet($key, $value, $ttl)
|
||||
|
||||
@@ -54,7 +54,7 @@ class FlexForm implements FlexFormInterface
|
||||
$this->setObject($object);
|
||||
$this->setId($this->getName());
|
||||
$this->setUniqueId(md5($uniqueId));
|
||||
$this->errors = [];
|
||||
$this->messages = [];
|
||||
$this->submitted = false;
|
||||
|
||||
$flash = $this->getFlash();
|
||||
|
||||
@@ -386,10 +386,6 @@ class FlexIndex extends ObjectIndex implements FlexCollectionInterface, FlexInde
|
||||
$cached = $result;
|
||||
}
|
||||
|
||||
if ($cached === null) {
|
||||
throw new \RuntimeException('Flex: Internal error');
|
||||
}
|
||||
|
||||
$cache->set($key, $cached);
|
||||
} catch (InvalidArgumentException $e) {
|
||||
$debugger->addException($e);
|
||||
|
||||
@@ -730,8 +730,8 @@ class FlexObject implements FlexObjectInterface, FlexAuthorizeInterface
|
||||
|
||||
$grav = Grav::instance();
|
||||
/** @var Flex $flex */
|
||||
$flex = $grav['flex_directory'];
|
||||
$directory = $flex->getDirectory($type);
|
||||
$flex = $grav['flex_objects'] ?? null;
|
||||
$directory = $flex ? $flex->getDirectory($type) : null;
|
||||
if (!$directory) {
|
||||
throw new \InvalidArgumentException("Cannot unserialize '{$type}': Not found");
|
||||
}
|
||||
|
||||
@@ -140,6 +140,11 @@ interface FormInterface extends RenderInterface, \Serializable
|
||||
*/
|
||||
public function isValid(): bool;
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getError(): ?string;
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
|
||||
@@ -30,6 +30,13 @@ use Twig\TemplateWrapper;
|
||||
*/
|
||||
trait FormTrait
|
||||
{
|
||||
/** @var string */
|
||||
public $status = 'success';
|
||||
/** @var string */
|
||||
public $message;
|
||||
/** @var string[] */
|
||||
public $messages = [];
|
||||
|
||||
/** @var string */
|
||||
private $name;
|
||||
/** @var string */
|
||||
@@ -38,8 +45,6 @@ trait FormTrait
|
||||
private $uniqueid;
|
||||
/** @var bool */
|
||||
private $submitted;
|
||||
/** @var string[] */
|
||||
private $errors;
|
||||
/** @var Data|object|null */
|
||||
private $data;
|
||||
/** @var array|UploadedFileInterface[] */
|
||||
@@ -164,12 +169,24 @@ trait FormTrait
|
||||
*/
|
||||
public function handleRequest(ServerRequestInterface $request): FormInterface
|
||||
{
|
||||
// Set current form to be active.
|
||||
$grav = Grav::instance();
|
||||
$forms = $grav['forms'] ?? null;
|
||||
if ($forms) {
|
||||
$forms->setActiveForm($this);
|
||||
|
||||
/** @var Twig $twig */
|
||||
$twig = $grav['twig'];
|
||||
$twig->twig_vars['form'] = $this;
|
||||
|
||||
}
|
||||
|
||||
try {
|
||||
[$data, $files] = $this->parseRequest($request);
|
||||
|
||||
$this->submit($data, $files);
|
||||
} catch (\Exception $e) {
|
||||
$this->errors[] = $e->getMessage();
|
||||
$this->setError($e->getMessage());
|
||||
}
|
||||
|
||||
return $this;
|
||||
@@ -191,12 +208,17 @@ trait FormTrait
|
||||
|
||||
public function isValid(): bool
|
||||
{
|
||||
return !$this->errors;
|
||||
return $this->status === 'success';
|
||||
}
|
||||
|
||||
public function getError(): ?string
|
||||
{
|
||||
return !$this->isValid() ? $this->message : null;
|
||||
}
|
||||
|
||||
public function getErrors(): array
|
||||
{
|
||||
return $this->errors;
|
||||
return !$this->isValid() ? $this->messages : [];
|
||||
}
|
||||
|
||||
public function isSubmitted(): bool
|
||||
@@ -206,7 +228,7 @@ trait FormTrait
|
||||
|
||||
public function validate(): bool
|
||||
{
|
||||
if ($this->errors) {
|
||||
if (!$this->isValid()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -214,19 +236,14 @@ trait FormTrait
|
||||
$this->validateData($this->data);
|
||||
$this->validateUploads($this->getFiles());
|
||||
} catch (ValidationException $e) {
|
||||
$list = [];
|
||||
foreach ($e->getMessages() as $field => $errors) {
|
||||
$list[] = $errors;
|
||||
}
|
||||
$list = array_merge(...$list);
|
||||
$this->errors = $list;
|
||||
$this->setErrors($e->getMessages());
|
||||
} catch (\Exception $e) {
|
||||
$this->errors[] = $e->getMessage();
|
||||
$this->setError($e->getMessage());
|
||||
}
|
||||
|
||||
$this->filterData($this->data);
|
||||
|
||||
return empty($this->errors);
|
||||
return $this->isValid();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -252,7 +269,7 @@ trait FormTrait
|
||||
|
||||
$this->submitted = true;
|
||||
} catch (\Exception $e) {
|
||||
$this->errors[] = $e->getMessage();
|
||||
$this->setError($e->getMessage());
|
||||
}
|
||||
|
||||
return $this;
|
||||
@@ -265,7 +282,9 @@ trait FormTrait
|
||||
|
||||
$this->data = null;
|
||||
$this->files = [];
|
||||
$this->errors = [];
|
||||
$this->status = 'success';
|
||||
$this->message = null;
|
||||
$this->messages = [];
|
||||
$this->submitted = false;
|
||||
$this->flash = null;
|
||||
}
|
||||
@@ -310,7 +329,6 @@ trait FormTrait
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
* Get form flash object.
|
||||
*
|
||||
* @return FormFlash
|
||||
@@ -376,16 +394,6 @@ trait FormTrait
|
||||
$this->flash = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set all errors.
|
||||
*
|
||||
* @param array $errors
|
||||
*/
|
||||
protected function setErrors(array $errors): void
|
||||
{
|
||||
$this->errors = array_merge($this->errors, $errors);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set a single error.
|
||||
*
|
||||
@@ -393,7 +401,19 @@ trait FormTrait
|
||||
*/
|
||||
protected function setError(string $error): void
|
||||
{
|
||||
$this->errors[] = $error;
|
||||
$this->status = 'error';
|
||||
$this->message = $error;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set all errors.
|
||||
*
|
||||
* @param array $errors
|
||||
*/
|
||||
protected function setErrors(array $errors): void
|
||||
{
|
||||
$this->status = 'error';
|
||||
$this->messages = $errors;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -563,7 +583,7 @@ trait FormTrait
|
||||
$value = json_decode($value, true);
|
||||
if ($value === null && json_last_error() !== JSON_ERROR_NONE) {
|
||||
unset($data[$key]);
|
||||
$this->errors[] = "Badly encoded JSON data (for {$key}) was sent to the form";
|
||||
$this->setError("Badly encoded JSON data (for {$key}) was sent to the form");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -583,7 +603,9 @@ trait FormTrait
|
||||
'id' => $this->id,
|
||||
'uniqueid' => $this->uniqueid,
|
||||
'submitted' => $this->submitted,
|
||||
'errors' => $this->errors,
|
||||
'status' => $this->status,
|
||||
'message' => $this->message,
|
||||
'messages' => $this->messages,
|
||||
'data' => $data,
|
||||
'files' => $this->files,
|
||||
];
|
||||
@@ -598,7 +620,9 @@ trait FormTrait
|
||||
$this->id = $data['id'];
|
||||
$this->uniqueid = $data['uniqueid'];
|
||||
$this->submitted = $data['submitted'] ?? false;
|
||||
$this->errors = $data['errors'] ?? [];
|
||||
$this->status = $data['status'] ?? 'success';
|
||||
$this->message = $data['message'] ?? null;
|
||||
$this->messages = $data['messages'] ?? [];
|
||||
$this->data = isset($data['data']) ? new Data($data['data'], $this->getBlueprint()) : null;
|
||||
$this->files = $data['files'] ?? [];
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user