mirror of
https://github.com/getgrav/grav.git
synced 2025-12-05 15:29:57 +01:00
Compare commits
23 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
2bc6848464 | ||
|
|
abefbfc776 | ||
|
|
ad173ca129 | ||
|
|
d69ef0e39c | ||
|
|
436be17881 | ||
|
|
9a5fa7e699 | ||
|
|
d502ff08c1 | ||
|
|
14eb1281f9 | ||
|
|
8fd7a5aebe | ||
|
|
08423df547 | ||
|
|
40563ed2f8 | ||
|
|
b639f09ca7 | ||
|
|
dd134ad551 | ||
|
|
3d93d50cf0 | ||
|
|
f1da7b6063 | ||
|
|
ef7b33f9b6 | ||
|
|
0f0e6ab1c8 | ||
|
|
5362b312d1 | ||
|
|
ca4d6a398f | ||
|
|
ed00d480f2 | ||
|
|
057bdd546b | ||
|
|
7762f0c85e | ||
|
|
4b777f508b |
28
CHANGELOG.md
28
CHANGELOG.md
@@ -1,3 +1,31 @@
|
||||
# v1.6.4
|
||||
## 04/15/2019
|
||||
|
||||
1. [](#bugfix)
|
||||
* Improved `redirect_default_route` logic as well as `Uri::toArray()` to take into account `root_path` and `extension`
|
||||
* Rework logic to pull out excluded files from pipeline more reliably [#2445](https://github.com/getgrav/grav/issues/2445)
|
||||
* Better logic in `Utils::normalizePath` to handle externals properly [#2216](https://github.com/getgrav/grav/issues/2216)
|
||||
* Fixed to force all `Page::taxonomy` to be treated as strings [#2446](https://github.com/getgrav/grav/issues/2446)
|
||||
* Fixed issue with `Grav['user']` not being available [form#332](https://github.com/getgrav/grav-plugin-form/issues/332)
|
||||
* Updated rounding logic for `Utils::parseSize()` [#2394](https://github.com/getgrav/grav/issues/2394)
|
||||
* Fixed Flex simple storage not being properly initialized if used with caching
|
||||
|
||||
# v1.6.3
|
||||
## 04/12/2019
|
||||
|
||||
1. [](#new)
|
||||
* Added `Blueprint::addDynamicHandler()` method to allow custom dynamic handlers, for example `custom-options@: getCustomOptions`
|
||||
1. [](#bugfix)
|
||||
* Missed a `CacheCommand` reference in `bin/grav` [#2442](https://github.com/getgrav/grav/issues/2442)
|
||||
* Fixed issue with `Utils::normalizePath` messing with external URLs [#2216](https://github.com/getgrav/grav/issues/2216)
|
||||
* Fix for `vUndefined` versions when upgrading
|
||||
|
||||
# v1.6.2
|
||||
## 04/11/2019
|
||||
|
||||
1. [](#bugfix)
|
||||
* Revert renaming of `ClearCacheCommand` to ensure CLI GPM upgrades go smoothly
|
||||
|
||||
# v1.6.1
|
||||
## 04/11/2019
|
||||
|
||||
|
||||
2
bin/grav
2
bin/grav
@@ -40,7 +40,7 @@ $app->addCommands(array(
|
||||
new \Grav\Console\Cli\ComposerCommand(),
|
||||
new \Grav\Console\Cli\SandboxCommand(),
|
||||
new \Grav\Console\Cli\CleanCommand(),
|
||||
new \Grav\Console\Cli\CacheCommand(),
|
||||
new \Grav\Console\Cli\ClearCacheCommand(),
|
||||
new \Grav\Console\Cli\BackupCommand(),
|
||||
new \Grav\Console\Cli\NewProjectCommand(),
|
||||
new \Grav\Console\Cli\SchedulerCommand(),
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
|
||||
// Some standard defines
|
||||
define('GRAV', true);
|
||||
define('GRAV_VERSION', '1.6.1');
|
||||
define('GRAV_VERSION', '1.6.4');
|
||||
define('GRAV_TESTING', false);
|
||||
define('DS', '/');
|
||||
|
||||
|
||||
@@ -45,8 +45,10 @@ class Assets extends PropertyObject
|
||||
|
||||
// Config Options
|
||||
protected $css_pipeline;
|
||||
protected $css_pipeline_include_externals;
|
||||
protected $css_pipeline_before_excludes;
|
||||
protected $js_pipeline;
|
||||
protected $js_pipeline_include_externals;
|
||||
protected $js_pipeline_before_excludes;
|
||||
protected $pipeline_options = [];
|
||||
|
||||
@@ -264,6 +266,21 @@ class Assets extends PropertyObject
|
||||
protected function filterAssets($assets, $key, $value, $sort = false)
|
||||
{
|
||||
$results = array_filter($assets, function($asset) use ($key, $value) {
|
||||
|
||||
if ($key === 'position' && $value === 'pipeline') {
|
||||
|
||||
$type = $asset->getType();
|
||||
|
||||
if ($asset->getRemote() && $this->{$type . '_pipeline_include_externals'} === false) {
|
||||
if ($this->{$type . '_pipeline_before_excludes'}) {
|
||||
$asset->setPosition('after');
|
||||
} else {
|
||||
$asset->setPosition('before');
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
if ($asset[$key] === $value) return true;
|
||||
return false;
|
||||
});
|
||||
@@ -292,11 +309,9 @@ class Assets extends PropertyObject
|
||||
$before_output = '';
|
||||
$pipeline_output = '';
|
||||
$after_output = '';
|
||||
$no_pipeline = [];
|
||||
|
||||
$assets = 'assets_' . $type;
|
||||
$pipeline_enabled = $type . '_pipeline';
|
||||
$before_excludes = $type . '_pipeline_before_excludes';
|
||||
$render_pipeline = 'render' . ucfirst($type);
|
||||
|
||||
$group_assets = $this->filterAssets($this->$assets, 'group', $group);
|
||||
@@ -309,22 +324,13 @@ class Assets extends PropertyObject
|
||||
$options = array_merge($this->pipeline_options, ['timestamp' => $this->timestamp]);
|
||||
|
||||
$pipeline = new Pipeline($options);
|
||||
$pipeline_output = $pipeline->$render_pipeline($pipeline_assets, $group, $attributes, $no_pipeline);
|
||||
$pipeline_output = $pipeline->$render_pipeline($pipeline_assets, $group, $attributes);
|
||||
} else {
|
||||
foreach ($pipeline_assets as $asset) {
|
||||
$pipeline_output .= $asset->render();
|
||||
}
|
||||
}
|
||||
|
||||
// Handle stuff that couldn't be pipelined
|
||||
if (!empty($no_pipeline)) {
|
||||
if ($this->{$before_excludes}) {
|
||||
$after_assets = array_merge($after_assets, $no_pipeline);
|
||||
} else {
|
||||
$before_assets = array_merge($before_assets, $no_pipeline);
|
||||
}
|
||||
}
|
||||
|
||||
// Before Pipeline
|
||||
foreach ($before_assets as $asset) {
|
||||
$before_output .= $asset->render();
|
||||
|
||||
@@ -129,6 +129,12 @@ abstract class BaseAsset extends PropertyObject
|
||||
return $this->remote;
|
||||
}
|
||||
|
||||
public function setPosition($position)
|
||||
{
|
||||
$this->position = $position;
|
||||
return $this;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
|
||||
@@ -50,9 +50,6 @@ class Pipeline extends PropertyObject
|
||||
protected $query;
|
||||
protected $asset;
|
||||
|
||||
protected $css_pipeline_include_externals;
|
||||
protected $js_pipeline_include_externals;
|
||||
|
||||
/**
|
||||
* Closure used by the pipeline to fetch assets.
|
||||
*
|
||||
@@ -91,11 +88,10 @@ class Pipeline extends PropertyObject
|
||||
* @param array $assets
|
||||
* @param string $group
|
||||
* @param array $attributes
|
||||
* @param array $no_pipeline
|
||||
*
|
||||
* @return bool|string URL or generated content if available, else false
|
||||
*/
|
||||
public function renderCss($assets, $group, $attributes = [], &$no_pipeline = [])
|
||||
public function renderCss($assets, $group, $attributes = [])
|
||||
{
|
||||
// temporary list of assets to pipeline
|
||||
$inline_group = false;
|
||||
@@ -119,21 +115,13 @@ class Pipeline extends PropertyObject
|
||||
if (file_exists($this->assets_dir . $file)) {
|
||||
$buffer = file_get_contents($this->assets_dir . $file) . "\n";
|
||||
} else {
|
||||
|
||||
foreach ($assets as $id => $asset) {
|
||||
if ($this->css_pipeline_include_externals === false && $asset->getRemote()) {
|
||||
$no_pipeline[$id] = $asset;
|
||||
unset($assets[$id]);
|
||||
}
|
||||
}
|
||||
|
||||
//if nothing found get out of here!
|
||||
if (empty($assets) && empty($no_pipeline)) {
|
||||
if (empty($assets)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Concatenate files
|
||||
$buffer = $this->gatherLinks($assets, self::CSS_ASSET, $no_pipeline);
|
||||
$buffer = $this->gatherLinks($assets, self::CSS_ASSET);
|
||||
|
||||
// Minify if required
|
||||
if ($this->shouldMinify('css')) {
|
||||
@@ -164,11 +152,10 @@ class Pipeline extends PropertyObject
|
||||
* @param array $assets
|
||||
* @param string $group
|
||||
* @param array $attributes
|
||||
* @param array $no_pipeline
|
||||
*
|
||||
* @return bool|string URL or generated content if available, else false
|
||||
*/
|
||||
public function renderJs($assets, $group, $attributes = [], &$no_pipeline = [])
|
||||
public function renderJs($assets, $group, $attributes = [])
|
||||
{
|
||||
// temporary list of assets to pipeline
|
||||
$inline_group = false;
|
||||
@@ -192,21 +179,13 @@ class Pipeline extends PropertyObject
|
||||
if (file_exists($this->assets_dir . $file)) {
|
||||
$buffer = file_get_contents($this->assets_dir . $file) . "\n";
|
||||
} else {
|
||||
|
||||
foreach ($assets as $id => $asset) {
|
||||
if ($this->js_pipeline_include_externals === false && $asset->getRemote()) {
|
||||
$no_pipeline[$id] = $asset;
|
||||
unset($assets[$id]);
|
||||
}
|
||||
}
|
||||
|
||||
//if nothing found get out of here!
|
||||
if (empty($assets) && empty($no_pipeline)) {
|
||||
if (empty($assets)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Concatenate files
|
||||
$buffer = $this->gatherLinks($assets, self::JS_ASSET, $no_pipeline);
|
||||
$buffer = $this->gatherLinks($assets, self::JS_ASSET);
|
||||
|
||||
// Minify if required
|
||||
if ($this->shouldMinify('js')) {
|
||||
|
||||
@@ -38,11 +38,10 @@ trait AssetUtilsTrait
|
||||
*
|
||||
* @param array $assets
|
||||
* @param bool $css
|
||||
* @param array $no_pipeline
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected function gatherLinks(array $assets, $css = true, &$no_pipeline = [])
|
||||
protected function gatherLinks(array $assets, $css = true)
|
||||
{
|
||||
$buffer = '';
|
||||
|
||||
@@ -74,9 +73,6 @@ trait AssetUtilsTrait
|
||||
|
||||
// No file found, skip it...
|
||||
if ($file === false) {
|
||||
if (!$local) { // Assume we couldn't download this file for some reason assume it's not pipeline compatible
|
||||
$no_pipeline[$id] = $asset;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
@@ -28,6 +28,15 @@ class Blueprint extends BlueprintForm
|
||||
/** @var array */
|
||||
protected $defaults;
|
||||
|
||||
protected $handlers = [];
|
||||
|
||||
public function __clone()
|
||||
{
|
||||
if ($this->blueprintSchema) {
|
||||
$this->blueprintSchema = clone $this->blueprintSchema;
|
||||
}
|
||||
}
|
||||
|
||||
public function setScope($scope)
|
||||
{
|
||||
$this->scope = $scope;
|
||||
@@ -66,6 +75,55 @@ class Blueprint extends BlueprintForm
|
||||
return $this->defaults;
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize blueprints with its dynamic fields.
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function init()
|
||||
{
|
||||
foreach ($this->dynamic as $key => $data) {
|
||||
// Locate field.
|
||||
$path = explode('/', $key);
|
||||
$current = &$this->items;
|
||||
|
||||
foreach ($path as $field) {
|
||||
if (\is_object($current)) {
|
||||
// Handle objects.
|
||||
if (!isset($current->{$field})) {
|
||||
$current->{$field} = [];
|
||||
}
|
||||
|
||||
$current = &$current->{$field};
|
||||
} else {
|
||||
// Handle arrays and scalars.
|
||||
if (!\is_array($current)) {
|
||||
$current = [$field => []];
|
||||
} elseif (!isset($current[$field])) {
|
||||
$current[$field] = [];
|
||||
}
|
||||
|
||||
$current = &$current[$field];
|
||||
}
|
||||
}
|
||||
|
||||
// Set dynamic property.
|
||||
foreach ($data as $property => $call) {
|
||||
$action = $call['action'];
|
||||
$method = 'dynamic' . ucfirst($action);
|
||||
|
||||
if (isset($this->handlers[$action])) {
|
||||
$callable = $this->handlers[$action];
|
||||
$callable($current, $property, $call);
|
||||
} elseif (method_exists($this, $method)) {
|
||||
$this->{$method}($current, $property, $call);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Merge two arrays by using blueprints.
|
||||
*
|
||||
@@ -165,6 +223,11 @@ class Blueprint extends BlueprintForm
|
||||
return $this->blueprintSchema;
|
||||
}
|
||||
|
||||
public function addDynamicHandler(string $name, callable $callable): void
|
||||
{
|
||||
$this->handlers[$name] = $callable;
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize validator.
|
||||
*/
|
||||
|
||||
@@ -12,11 +12,16 @@ namespace Grav\Common\GPM\Remote;
|
||||
use Grav\Common\Data\Data;
|
||||
use Grav\Common\GPM\Common\Package as BasePackage;
|
||||
|
||||
class Package extends BasePackage
|
||||
class Package extends BasePackage implements \JsonSerializable
|
||||
{
|
||||
public function __construct($package, $package_type = null)
|
||||
{
|
||||
$data = new Data($package);
|
||||
parent::__construct($data, $package_type);
|
||||
}
|
||||
|
||||
public function jsonSerialize()
|
||||
{
|
||||
return $this->data;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -414,9 +414,7 @@ class Page implements PageInterface
|
||||
$this->markdown_extra = (bool)$this->header->markdown_extra;
|
||||
}
|
||||
if (isset($this->header->taxonomy)) {
|
||||
foreach ((array)$this->header->taxonomy as $taxonomy => $taxitems) {
|
||||
$this->taxonomy[$taxonomy] = (array)$taxitems;
|
||||
}
|
||||
$this->taxonomy($this->header->taxonomy);
|
||||
}
|
||||
if (isset($this->header->max_count)) {
|
||||
$this->max_count = (int)$this->header->max_count;
|
||||
@@ -2296,6 +2294,14 @@ class Page implements PageInterface
|
||||
public function taxonomy($var = null)
|
||||
{
|
||||
if ($var !== null) {
|
||||
// make sure first level are arrays
|
||||
array_walk($var, function(&$value) {
|
||||
$value = (array) $value;
|
||||
});
|
||||
// make sure all values are strings
|
||||
array_walk_recursive($var, function(&$value) {
|
||||
$value = (string) $value;
|
||||
});
|
||||
$this->taxonomy = $var;
|
||||
}
|
||||
|
||||
|
||||
@@ -80,6 +80,8 @@ class PagesServiceProvider implements ServiceProviderInterface
|
||||
}
|
||||
// Default route test and redirect
|
||||
if ($config->get('system.pages.redirect_default_route') && $page->route() !== $path) {
|
||||
$uri->setUriProperties(['path' => $page->route()]);
|
||||
$url = (string) $uri;
|
||||
$c->redirect($url);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -187,11 +187,9 @@ class Uri
|
||||
$this->extension = $parts['extension'];
|
||||
}
|
||||
|
||||
$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'])) {
|
||||
$path = rtrim(str_replace(DIRECTORY_SEPARATOR, DS, $parts['dirname']), DS) . '/' . $parts['filename'];
|
||||
if ($this->isValidExtension($this->extension)) {
|
||||
$path = Utils::replaceLastOccurrence(".{$this->extension}", '', $path);
|
||||
}
|
||||
|
||||
// set the new url
|
||||
@@ -586,13 +584,16 @@ class Uri
|
||||
|
||||
public function toArray()
|
||||
{
|
||||
$root_path = $this->root_path ?? '';
|
||||
$extension = isset($this->extension) && $this->isValidExtension($this->extension) ? '.' . $this->extension : '';
|
||||
$path = $root_path . $this->path . $extension;
|
||||
return [
|
||||
'scheme' => $this->scheme,
|
||||
'host' => $this->host,
|
||||
'port' => $this->port,
|
||||
'user' => $this->user,
|
||||
'pass' => $this->password,
|
||||
'path' => $this->path,
|
||||
'path' => $path,
|
||||
'params' => $this->params,
|
||||
'query' => $this->query,
|
||||
'fragment' => $this->fragment
|
||||
@@ -1326,6 +1327,38 @@ class Uri
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if this is a valid Grav extension
|
||||
*
|
||||
* @param $extension
|
||||
* @return bool
|
||||
*/
|
||||
public function isValidExtension($extension)
|
||||
{
|
||||
$valid_page_types = implode('|', Grav::instance()['config']->get('system.pages.types'));
|
||||
|
||||
// Strip the file extension for valid page types
|
||||
if (preg_match('/(' . $valid_page_types . ')/', $extension)) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Allow overriding of any element (be careful!)
|
||||
*
|
||||
* @param $data
|
||||
* @return Uri
|
||||
*/
|
||||
public function setUriProperties($data)
|
||||
{
|
||||
foreach (get_object_vars($this) as $property => $default) {
|
||||
if (!array_key_exists($property, $data)) continue;
|
||||
$this->{$property} = $data[$property]; // assign value to object
|
||||
}
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the base URI with port if needed
|
||||
*
|
||||
|
||||
@@ -20,7 +20,9 @@ abstract class Utils
|
||||
{
|
||||
protected static $nonces = [];
|
||||
|
||||
protected const ROOTURL_REGEX = '{^(\/*)}';
|
||||
protected const ROOTURL_REGEX = '{^((?:http[s]?:\/\/[^\/]+)|(?:\/\/[^\/]+))(.*)}';
|
||||
|
||||
// ^((?:http[s]?:)?[\/]?(?:\/))
|
||||
|
||||
/**
|
||||
* Simple helper method to make getting a Grav URL easier
|
||||
@@ -784,26 +786,46 @@ abstract class Utils
|
||||
*/
|
||||
public static function normalizePath($path)
|
||||
{
|
||||
// Resolve any streams
|
||||
/** @var UniformResourceLocator $locator */
|
||||
$locator = Grav::instance()['locator'];
|
||||
if ($locator->isStream($path)) {
|
||||
$path = $locator->findResource($path);
|
||||
}
|
||||
|
||||
// Set root properly for any URLs
|
||||
$root = '';
|
||||
preg_match(self::ROOTURL_REGEX, $path, $matches);
|
||||
if ($matches) {
|
||||
$root = $matches[0];
|
||||
$root = $matches[1];
|
||||
$path = $matches[2];
|
||||
}
|
||||
|
||||
$clean_path = static::replaceFirstOccurrence($root, '', $path);
|
||||
$segments = explode('/', trim($clean_path, '/'));
|
||||
$ret = [];
|
||||
foreach ($segments as $segment) {
|
||||
if (($segment === '.') || $segment === '') {
|
||||
continue;
|
||||
}
|
||||
if ($segment === '..') {
|
||||
array_pop($ret);
|
||||
} else {
|
||||
$ret[] = $segment;
|
||||
}
|
||||
// Strip off leading / to ensure explode is accurate
|
||||
if (Utils::startsWith($path,'/')) {
|
||||
$root .= '/';
|
||||
$path = ltrim($path, '/');
|
||||
}
|
||||
$normalized = $root . implode('/', $ret);
|
||||
|
||||
// If there are any relative paths (..) handle those
|
||||
if (Utils::contains($path, '..')) {
|
||||
$segments = explode('/', trim($path, '/'));
|
||||
$ret = [];
|
||||
foreach ($segments as $segment) {
|
||||
if (($segment === '.') || $segment === '') {
|
||||
continue;
|
||||
}
|
||||
if ($segment === '..') {
|
||||
array_pop($ret);
|
||||
} else {
|
||||
$ret[] = $segment;
|
||||
}
|
||||
}
|
||||
$path = implode('/', $ret);
|
||||
}
|
||||
|
||||
// Stick everything back together
|
||||
$normalized = $root . $path;
|
||||
return $normalized;
|
||||
}
|
||||
|
||||
@@ -1383,10 +1405,10 @@ abstract class Utils
|
||||
$unit = preg_replace('/[^bkmgtpezy]/i', '', $size);
|
||||
$size = preg_replace('/[^0-9\.]/', '', $size);
|
||||
if ($unit) {
|
||||
return (int)((int)$size * (1024 ** stripos('bkmgtpezy', $unit[0])));
|
||||
return round($size * pow(1024, stripos('bkmgtpezy', $unit[0])));
|
||||
} else {
|
||||
return round($size);
|
||||
}
|
||||
|
||||
return (int)$size;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -13,7 +13,7 @@ use Grav\Common\Cache;
|
||||
use Grav\Console\ConsoleCommand;
|
||||
use Symfony\Component\Console\Input\InputOption;
|
||||
|
||||
class CacheCommand extends ConsoleCommand
|
||||
class ClearCacheCommand extends ConsoleCommand
|
||||
{
|
||||
protected function configure()
|
||||
{
|
||||
@@ -13,7 +13,7 @@ use Grav\Common\Cache;
|
||||
use Grav\Common\Grav;
|
||||
use Grav\Common\Composer;
|
||||
use Grav\Common\GravTrait;
|
||||
use Grav\Console\Cli\CacheCommand;
|
||||
use Grav\Console\Cli\ClearCacheCommand;
|
||||
use RocketTheme\Toolbox\File\YamlFile;
|
||||
use Symfony\Component\Console\Formatter\OutputFormatterStyle;
|
||||
use Symfony\Component\Console\Input\ArrayInput;
|
||||
@@ -107,7 +107,7 @@ trait ConsoleTrait
|
||||
$all = ['--all' => true];
|
||||
}
|
||||
|
||||
$command = new CacheCommand();
|
||||
$command = new ClearCacheCommand();
|
||||
$input = new ArrayInput($all);
|
||||
return $command->run($input, $this->output);
|
||||
}
|
||||
|
||||
@@ -71,7 +71,7 @@ class FolderStorage extends AbstractFilesystemStorage
|
||||
*/
|
||||
public function hasKey(string $key): bool
|
||||
{
|
||||
return $key && !strpos($key, '@@') && file_exists($this->getPathFromKey($key));
|
||||
return $key && strpos($key, '@@') === false && file_exists($this->getPathFromKey($key));
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -71,7 +71,11 @@ class SimpleStorage extends AbstractFilesystemStorage
|
||||
*/
|
||||
public function hasKey(string $key): bool
|
||||
{
|
||||
return $key && !strpos($key, '@@') && isset($this->data[$key]);
|
||||
if (null === $this->data) {
|
||||
$this->buildIndex();
|
||||
}
|
||||
|
||||
return $key && strpos($key, '@@') === false && isset($this->data[$key]);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -80,6 +84,10 @@ class SimpleStorage extends AbstractFilesystemStorage
|
||||
*/
|
||||
public function createRows(array $rows): array
|
||||
{
|
||||
if (null === $this->data) {
|
||||
$this->buildIndex();
|
||||
}
|
||||
|
||||
$list = [];
|
||||
foreach ($rows as $key => $row) {
|
||||
$key = $this->getNewKey();
|
||||
@@ -99,6 +107,10 @@ class SimpleStorage extends AbstractFilesystemStorage
|
||||
*/
|
||||
public function readRows(array $rows, array &$fetched = null): array
|
||||
{
|
||||
if (null === $this->data) {
|
||||
$this->buildIndex();
|
||||
}
|
||||
|
||||
$list = [];
|
||||
foreach ($rows as $key => $row) {
|
||||
if (null === $row || (!\is_object($row) && !\is_array($row))) {
|
||||
@@ -123,6 +135,10 @@ class SimpleStorage extends AbstractFilesystemStorage
|
||||
*/
|
||||
public function updateRows(array $rows): array
|
||||
{
|
||||
if (null === $this->data) {
|
||||
$this->buildIndex();
|
||||
}
|
||||
|
||||
$list = [];
|
||||
foreach ($rows as $key => $row) {
|
||||
$key = (string)$key;
|
||||
@@ -144,6 +160,10 @@ class SimpleStorage extends AbstractFilesystemStorage
|
||||
*/
|
||||
public function deleteRows(array $rows): array
|
||||
{
|
||||
if (null === $this->data) {
|
||||
$this->buildIndex();
|
||||
}
|
||||
|
||||
$list = [];
|
||||
foreach ($rows as $key => $row) {
|
||||
$key = (string)$key;
|
||||
@@ -166,6 +186,10 @@ class SimpleStorage extends AbstractFilesystemStorage
|
||||
*/
|
||||
public function replaceRows(array $rows): array
|
||||
{
|
||||
if (null === $this->data) {
|
||||
$this->buildIndex();
|
||||
}
|
||||
|
||||
$list = [];
|
||||
foreach ($rows as $key => $row) {
|
||||
$this->data[$key] = $list[$key] = $row;
|
||||
@@ -184,6 +208,10 @@ class SimpleStorage extends AbstractFilesystemStorage
|
||||
*/
|
||||
public function renameRow(string $src, string $dst): bool
|
||||
{
|
||||
if (null === $this->data) {
|
||||
$this->buildIndex();
|
||||
}
|
||||
|
||||
if ($this->hasKey($dst)) {
|
||||
throw new \RuntimeException("Cannot rename object: key '{$dst}' is already taken");
|
||||
}
|
||||
@@ -221,6 +249,10 @@ class SimpleStorage extends AbstractFilesystemStorage
|
||||
|
||||
protected function save() : void
|
||||
{
|
||||
if (null === $this->data) {
|
||||
$this->buildIndex();
|
||||
}
|
||||
|
||||
try {
|
||||
$file = $this->getFile($this->getStoragePath());
|
||||
$file->save($this->data);
|
||||
|
||||
@@ -16,7 +16,6 @@ use Grav\Common\Form\FormFlash;
|
||||
use Grav\Common\Grav;
|
||||
use Grav\Common\Utils;
|
||||
use Grav\Framework\Form\Interfaces\FormInterface;
|
||||
use Grav\Framework\Session\Session;
|
||||
use Psr\Http\Message\ServerRequestInterface;
|
||||
use Psr\Http\Message\UploadedFileInterface;
|
||||
|
||||
@@ -309,24 +308,30 @@ trait FormTrait
|
||||
public function getFlash(): FormFlash
|
||||
{
|
||||
if (null === $this->flash) {
|
||||
/** @var Grav $grav */
|
||||
$grav = Grav::instance();
|
||||
$user = $grav['user'];
|
||||
$id = null;
|
||||
|
||||
$rememberState = $this->getBlueprint()->get('form/remember_state');
|
||||
if ($rememberState === 'user') {
|
||||
$id = $user->username;
|
||||
$user = $grav['user'] ?? null;
|
||||
if (isset($user)) {
|
||||
$rememberState = $this->getBlueprint()->get('form/remember_state');
|
||||
if ($rememberState === 'user') {
|
||||
$id = $user->username;
|
||||
}
|
||||
}
|
||||
|
||||
// By default store flash by the session id.
|
||||
if (null === $id) {
|
||||
/** @var Session $session */
|
||||
$session = $grav['session'];
|
||||
$id = $session->getId();
|
||||
}
|
||||
// Session Required for flash form
|
||||
$session = $grav['session'] ?? null;
|
||||
if (isset($session)) {
|
||||
// By default store flash by the session id.
|
||||
if (null === $id) {
|
||||
$id = $session->getId();
|
||||
}
|
||||
|
||||
$this->flash = new FormFlash($id, $this->getUniqueId(), $this->getName());
|
||||
$this->flash->setUrl($grav['uri']->url)->setUser($user);
|
||||
|
||||
$this->flash = new FormFlash($id, $this->getUniqueId(), $this->getName());
|
||||
$this->flash->setUrl($grav['uri']->url)->setUser($user);
|
||||
}
|
||||
}
|
||||
|
||||
return $this->flash;
|
||||
|
||||
@@ -573,7 +573,7 @@ class UriTest extends \Codeception\TestCase\Test
|
||||
'rootUrl' => 'http://localhost',
|
||||
'extension' => 'html',
|
||||
'addNonce' => 'http://localhost/a-page.html/nonce:{{nonce}}',
|
||||
'__toString' => 'http://localhost/a-page', // FIXME <-
|
||||
'__toString' => 'http://localhost/a-page.html',
|
||||
],
|
||||
'http://localhost/a-page.json' => [
|
||||
'scheme' => 'http://',
|
||||
@@ -596,7 +596,7 @@ class UriTest extends \Codeception\TestCase\Test
|
||||
'rootUrl' => 'http://localhost',
|
||||
'extension' => 'json',
|
||||
'addNonce' => 'http://localhost/a-page.json/nonce:{{nonce}}',
|
||||
'__toString' => 'http://localhost/a-page', // FIX ME <-
|
||||
'__toString' => 'http://localhost/a-page.json',
|
||||
],
|
||||
'http://localhost/admin/ajax.json/task:getnewsfeed' => [
|
||||
'scheme' => 'http://',
|
||||
@@ -619,7 +619,7 @@ class UriTest extends \Codeception\TestCase\Test
|
||||
'rootUrl' => 'http://localhost',
|
||||
'extension' => 'json',
|
||||
'addNonce' => 'http://localhost/admin/ajax.json/task:getnewsfeed/nonce:{{nonce}}',
|
||||
'__toString' => 'http://localhost/admin/ajax/task:getnewsfeed',
|
||||
'__toString' => 'http://localhost/admin/ajax.json/task:getnewsfeed',
|
||||
],
|
||||
'http://localhost/grav/admin/media.json/route:L1VzZXJzL3JodWsvd29ya3NwYWNlL2dyYXYtZGVtby1zYW1wbGVyL3VzZXIvYXNzZXRzL3FRMXB4Vk1ERTNJZzh5Ni5qcGc=/task:removeFileFromBlueprint/proute:/blueprint:Y29uZmlnL2RldGFpbHM=/type:config/field:deep.nested.custom_file/path:dXNlci9hc3NldHMvcVExcHhWTURFM0lnOHk2LmpwZw==' => [
|
||||
'scheme' => 'http://',
|
||||
@@ -642,7 +642,7 @@ class UriTest extends \Codeception\TestCase\Test
|
||||
'rootUrl' => 'http://localhost',
|
||||
'extension' => 'json',
|
||||
'addNonce' => 'http://localhost/grav/admin/media.json/route:L1VzZXJzL3JodWsvd29ya3NwYWNlL2dyYXYtZGVtby1zYW1wbGVyL3VzZXIvYXNzZXRzL3FRMXB4Vk1ERTNJZzh5Ni5qcGc=/task:removeFileFromBlueprint/proute:/blueprint:Y29uZmlnL2RldGFpbHM=/type:config/field:deep.nested.custom_file/path:dXNlci9hc3NldHMvcVExcHhWTURFM0lnOHk2LmpwZw==/nonce:{{nonce}}',
|
||||
'__toString' => 'http://localhost/grav/admin/media/route:L1VzZXJzL3JodWsvd29ya3NwYWNlL2dyYXYtZGVtby1zYW1wbGVyL3VzZXIvYXNzZXRzL3FRMXB4Vk1ERTNJZzh5Ni5qcGc=/task:removeFileFromBlueprint/proute:/blueprint:Y29uZmlnL2RldGFpbHM=/type:config/field:deep.nested.custom_file/path:dXNlci9hc3NldHMvcVExcHhWTURFM0lnOHk2LmpwZw==', // FIXME <-
|
||||
'__toString' => 'http://localhost/grav/admin/media.json/route:L1VzZXJzL3JodWsvd29ya3NwYWNlL2dyYXYtZGVtby1zYW1wbGVyL3VzZXIvYXNzZXRzL3FRMXB4Vk1ERTNJZzh5Ni5qcGc=/task:removeFileFromBlueprint/proute:/blueprint:Y29uZmlnL2RldGFpbHM=/type:config/field:deep.nested.custom_file/path:dXNlci9hc3NldHMvcVExcHhWTURFM0lnOHk2LmpwZw==',
|
||||
],
|
||||
'http://localhost/a-page.foo' => [
|
||||
'scheme' => 'http://',
|
||||
@@ -1121,6 +1121,24 @@ class UriTest extends \Codeception\TestCase\Test
|
||||
];
|
||||
|
||||
$this->assertSame('http://foo:bar@localhost:8080/test?x=2#xxx', Uri::buildUrl($parsed_url));
|
||||
|
||||
/** @var Uri $uri */
|
||||
$uri = Grav::instance()['uri'];
|
||||
|
||||
$uri->initializeWithUrlAndRootPath('https://testing.dev/subdir/path1/path2/file.html', '/subdir')->init();
|
||||
$this->assertSame('https://testing.dev/subdir/path1/path2/file.html', Uri::buildUrl($uri->toArray()));
|
||||
|
||||
$uri->initializeWithUrlAndRootPath('https://testing.dev/subdir/path1/path2/file.foo', '/subdir')->init();
|
||||
$this->assertSame('https://testing.dev/subdir/path1/path2/file.foo', Uri::buildUrl($uri->toArray()));
|
||||
|
||||
$uri->initializeWithUrlAndRootPath('https://testing.dev/subdir/path1/path2/file.html', '/subdir/path1')->init();
|
||||
$this->assertSame('https://testing.dev/subdir/path1/path2/file.html', Uri::buildUrl($uri->toArray()));
|
||||
|
||||
$uri->initializeWithUrlAndRootPath('https://testing.dev/subdir/path1/path2/file.html/foo:blah/bang:boom', '/subdir')->init();
|
||||
$this->assertSame('https://testing.dev/subdir/path1/path2/file.html/foo:blah/bang:boom', Uri::buildUrl($uri->toArray()));
|
||||
|
||||
$uri->initializeWithUrlAndRootPath('https://testing.dev/subdir/path1/path2/file.html/foo:blah/bang:boom?fig=something', '/subdir')->init();
|
||||
$this->assertSame('https://testing.dev/subdir/path1/path2/file.html/foo:blah/bang:boom?fig=something', Uri::buildUrl($uri->toArray()));
|
||||
}
|
||||
|
||||
public function testConvertUrl()
|
||||
|
||||
@@ -224,10 +224,19 @@ class UtilsTest extends \Codeception\TestCase\Test
|
||||
$this->assertEquals('test', Utils::normalizePath('../test'));
|
||||
$this->assertEquals('/test', Utils::normalizePath('/../test'));
|
||||
$this->assertEquals('/test2', Utils::normalizePath('/test/../test2'));
|
||||
$this->assertEquals('/test/test2', Utils::normalizePath('/test/./test2'));
|
||||
$this->assertEquals('//something/test/test2', Utils::normalizePath('//../something/test/test2'));
|
||||
$this->assertEquals('//something/test2', Utils::normalizePath('//something/test/../test2'));
|
||||
$this->assertEquals('//test2', Utils::normalizePath('//something/../test/../test2'));
|
||||
$this->assertEquals('/test3', Utils::normalizePath('/test/../test2/../test3'));
|
||||
|
||||
$this->assertEquals('//cdnjs.cloudflare.com/ajax/libs/Leaflet.awesome-markers/2.0.2/leaflet.awesome-markers.css', Utils::normalizePath('//cdnjs.cloudflare.com/ajax/libs/Leaflet.awesome-markers/2.0.2/leaflet.awesome-markers.css'));
|
||||
$this->assertEquals('//use.fontawesome.com/releases/v5.8.1/css/all.css', Utils::normalizePath('//use.fontawesome.com/releases/v5.8.1/css/all.css'));
|
||||
$this->assertEquals('//use.fontawesome.com/releases/v5.8.1/webfonts/fa-brands-400.eot', Utils::normalizePath('//use.fontawesome.com/releases/v5.8.1/css/../webfonts/fa-brands-400.eot'));
|
||||
|
||||
$this->assertEquals('http://cdnjs.cloudflare.com/ajax/libs/Leaflet.awesome-markers/2.0.2/leaflet.awesome-markers.css', Utils::normalizePath('http://cdnjs.cloudflare.com/ajax/libs/Leaflet.awesome-markers/2.0.2/leaflet.awesome-markers.css'));
|
||||
$this->assertEquals('http://use.fontawesome.com/releases/v5.8.1/css/all.css', Utils::normalizePath('http://use.fontawesome.com/releases/v5.8.1/css/all.css'));
|
||||
$this->assertEquals('http://use.fontawesome.com/releases/v5.8.1/webfonts/fa-brands-400.eot', Utils::normalizePath('http://use.fontawesome.com/releases/v5.8.1/css/../webfonts/fa-brands-400.eot'));
|
||||
|
||||
$this->assertEquals('https://cdnjs.cloudflare.com/ajax/libs/Leaflet.awesome-markers/2.0.2/leaflet.awesome-markers.css', Utils::normalizePath('https://cdnjs.cloudflare.com/ajax/libs/Leaflet.awesome-markers/2.0.2/leaflet.awesome-markers.css'));
|
||||
$this->assertEquals('https://use.fontawesome.com/releases/v5.8.1/css/all.css', Utils::normalizePath('https://use.fontawesome.com/releases/v5.8.1/css/all.css'));
|
||||
$this->assertEquals('https://use.fontawesome.com/releases/v5.8.1/webfonts/fa-brands-400.eot', Utils::normalizePath('https://use.fontawesome.com/releases/v5.8.1/css/../webfonts/fa-brands-400.eot'));
|
||||
}
|
||||
|
||||
public function testIsFunctionDisabled()
|
||||
|
||||
Reference in New Issue
Block a user