mirror of
https://github.com/getgrav/grav.git
synced 2026-03-04 11:31:43 +01:00
Merge branch 'release/1.7.19'
This commit is contained in:
@@ -13,5 +13,5 @@ indent_size = 4
|
||||
trim_trailing_whitespace = true
|
||||
|
||||
# 2 space indentation
|
||||
[*.{yaml,yml}]
|
||||
[*.{yaml,yml,vue,js,css}]
|
||||
indent_size = 2
|
||||
|
||||
1
.gitignore
vendored
1
.gitignore
vendored
@@ -45,3 +45,4 @@ tests/cache/*
|
||||
tests/error.log
|
||||
system/templates/testing/*
|
||||
/user/config/versions.yaml
|
||||
/user/cli/config/security.yaml
|
||||
|
||||
25
CHANGELOG.md
25
CHANGELOG.md
@@ -1,3 +1,28 @@
|
||||
# v1.7.19
|
||||
## 08/31/2021
|
||||
|
||||
1. [](#new)
|
||||
* Include active form and request in `onPageTask` and `onPageAction` events (defaults to `null`)
|
||||
* Added `UserObject::$authorizeCallable` to allow `$user->authorize()` customization
|
||||
2. [](#improved)
|
||||
* Added meta support for `UploadedFile` class
|
||||
* Added support for multiple mime-types per file extension [#3422](https://github.com/getgrav/grav/issues/3422)
|
||||
* Added `setCurrent()` method to Page Collection [#3398](https://github.com/getgrav/grav/pull/3398)
|
||||
* Initialize `$grav['uri']` before session
|
||||
3. [](#bugfix)
|
||||
* Fixed `Warning: Undefined array key "SERVER_SOFTWARE" in index.php` [#3408](https://github.com/getgrav/grav/issues/3408)
|
||||
* Fixed error in `loadDirectoryConfig()` if configuration hasn't been saved [#3409](https://github.com/getgrav/grav/issues/3409)
|
||||
* Fixed GPM not using non-standard cache path [#3410](https://github.com/getgrav/grav/issues/3410)
|
||||
* Fixed broken `environment://` stream when it doesn't have configuration
|
||||
* Fixed `Flex Object` missing key field value when using `FolderStorage`
|
||||
* Fixed broken Twig try tag when catch has not been defined or is empty
|
||||
* Fixed `FlexForm` serialization
|
||||
* Fixed form validation for numeric values in PHP 8
|
||||
* Fixed `flex-options@` in blueprints duplicating items in array
|
||||
* Fixed wrong form issue with flex objects after cache clear
|
||||
* Fixed Flex object types not implementing `MediaInterface`
|
||||
* Fixed issue with `svgImageFunction()` that was causing broken output
|
||||
|
||||
# v1.7.18
|
||||
## 07/19/2021
|
||||
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
#  Grav
|
||||
|
||||
[](https://github.com/phpstan/phpstan)
|
||||
[](https://insight.sensiolabs.com/projects/cfd20465-d0f8-4a0a-8444-467f5b5f16ad)
|
||||
[](https://chat.getgrav.org)
|
||||
[](https://github.com/getgrav/grav/actions?query=workflow%3A%22PHP+Tests%22) [](#backers) [](#sponsors)
|
||||
|
||||
|
||||
366
composer.lock
generated
366
composer.lock
generated
File diff suppressed because it is too large
Load Diff
@@ -17,7 +17,7 @@ if (version_compare($ver = PHP_VERSION, $req = GRAV_PHP_MIN, '<')) {
|
||||
}
|
||||
|
||||
if (PHP_SAPI === 'cli-server') {
|
||||
$symfony_server = stripos(getenv('_'), 'symfony') !== false || stripos($_SERVER['SERVER_SOFTWARE'], 'symfony') !== false || stripos($_ENV['SERVER_SOFTWARE'], 'symfony') !== false;
|
||||
$symfony_server = stripos(getenv('_'), 'symfony') !== false || stripos($_SERVER['SERVER_SOFTWARE'] ?? '', 'symfony') !== false || stripos($_ENV['SERVER_SOFTWARE'] ?? '', 'symfony') !== false;
|
||||
|
||||
if (!isset($_SERVER['PHP_CLI_ROUTER']) && !$symfony_server) {
|
||||
die("PHP webserver requires a router to run Grav, please use: <pre>php -S {$_SERVER['SERVER_NAME']}:{$_SERVER['SERVER_PORT']} system/router.php</pre>");
|
||||
|
||||
@@ -28,6 +28,10 @@ types:
|
||||
type: image
|
||||
thumb: media/thumb-webp.png
|
||||
mime: image/webp
|
||||
avif:
|
||||
type: image
|
||||
thumb: media/thumb.png
|
||||
mime: image/avif
|
||||
gif:
|
||||
type: animated
|
||||
thumb: media/thumb-gif.png
|
||||
@@ -91,7 +95,7 @@ types:
|
||||
aif:
|
||||
type: audio
|
||||
thumb: media/thumb-aif.png
|
||||
mime: audio/aif
|
||||
mime: audio/aiff
|
||||
txt:
|
||||
type: file
|
||||
thumb: media/thumb-txt.png
|
||||
@@ -207,7 +211,7 @@ types:
|
||||
js:
|
||||
type: file
|
||||
thumb: media/thumb-js.png
|
||||
mime: application/javascript
|
||||
mime: text/javascript
|
||||
json:
|
||||
type: file
|
||||
thumb: media/thumb-json.png
|
||||
|
||||
1986
system/config/mime.yaml
Normal file
1986
system/config/mime.yaml
Normal file
File diff suppressed because it is too large
Load Diff
@@ -9,7 +9,7 @@
|
||||
|
||||
// Some standard defines
|
||||
define('GRAV', true);
|
||||
define('GRAV_VERSION', '1.7.18');
|
||||
define('GRAV_VERSION', '1.7.19');
|
||||
define('GRAV_SCHEMA', '1.7.0_2020-11-20_1');
|
||||
define('GRAV_TESTING', false);
|
||||
|
||||
|
||||
@@ -41,6 +41,9 @@ class Setup extends Data
|
||||
*/
|
||||
public static $environment;
|
||||
|
||||
/** @var string */
|
||||
public static $securityFile = 'config://security.yaml';
|
||||
|
||||
/** @var array */
|
||||
protected $streams = [
|
||||
'user' => [
|
||||
@@ -390,12 +393,15 @@ class Setup extends Data
|
||||
|
||||
if (!$locator->findResource('environment://config', true)) {
|
||||
// If environment does not have its own directory, remove it from the lookup.
|
||||
$this->set('streams.schemes.environment.prefixes', ['config' => []]);
|
||||
$prefixes = $this->get('streams.schemes.environment.prefixes');
|
||||
$prefixes['config'] = [];
|
||||
|
||||
$this->set('streams.schemes.environment.prefixes', $prefixes);
|
||||
$this->initializeLocator($locator);
|
||||
}
|
||||
|
||||
// Create security.yaml if it doesn't exist.
|
||||
$filename = $locator->findResource('config://security.yaml', true, true);
|
||||
$filename = $locator->findResource(static::$securityFile, true, true);
|
||||
$security_file = CompiledYamlFile::instance($filename);
|
||||
$security_content = (array)$security_file->content();
|
||||
|
||||
|
||||
@@ -519,17 +519,30 @@ class Validation
|
||||
return false;
|
||||
}
|
||||
|
||||
if (isset($params['min']) && $value < $params['min']) {
|
||||
return false;
|
||||
$value = (float)$value;
|
||||
|
||||
$min = 0;
|
||||
if (isset($params['min'])) {
|
||||
$min = (float)$params['min'];
|
||||
if ($value < $min) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (isset($params['max']) && $value > $params['max']) {
|
||||
return false;
|
||||
if (isset($params['max'])) {
|
||||
$max = (float)$params['max'];
|
||||
if ($value > $max) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
$min = $params['min'] ?? 0;
|
||||
if (isset($params['step'])) {
|
||||
$step = (float)$params['step'];
|
||||
|
||||
return !(isset($params['step']) && fmod($value - $min, $params['step']) === 0);
|
||||
return fmod($value - $min, $step) === 0.0;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -13,6 +13,7 @@ namespace Grav\Common\Flex;
|
||||
|
||||
use Grav\Common\Flex\Traits\FlexGravTrait;
|
||||
use Grav\Common\Flex\Traits\FlexObjectTrait;
|
||||
use Grav\Common\Media\Interfaces\MediaInterface;
|
||||
use Grav\Framework\Flex\Traits\FlexMediaTrait;
|
||||
use function is_array;
|
||||
|
||||
@@ -21,7 +22,7 @@ use function is_array;
|
||||
*
|
||||
* @package Grav\Common\Flex
|
||||
*/
|
||||
abstract class FlexObject extends \Grav\Framework\Flex\FlexObject
|
||||
abstract class FlexObject extends \Grav\Framework\Flex\FlexObject implements MediaInterface
|
||||
{
|
||||
use FlexGravTrait;
|
||||
use FlexObjectTrait;
|
||||
|
||||
@@ -192,6 +192,14 @@ class PageCollection extends FlexPageCollection implements PageCollectionInterfa
|
||||
throw new RuntimeException(__METHOD__ . '(): Not Implemented');
|
||||
}
|
||||
|
||||
/**
|
||||
* Set current page.
|
||||
*/
|
||||
public function setCurrent(string $path): void
|
||||
{
|
||||
throw new RuntimeException(__METHOD__ . '(): Not Implemented');
|
||||
}
|
||||
|
||||
/**
|
||||
* Return previous item.
|
||||
*
|
||||
|
||||
@@ -11,6 +11,7 @@ declare(strict_types=1);
|
||||
|
||||
namespace Grav\Common\Flex\Types\Users;
|
||||
|
||||
use Closure;
|
||||
use Countable;
|
||||
use Grav\Common\Config\Config;
|
||||
use Grav\Common\Data\Blueprint;
|
||||
@@ -75,6 +76,9 @@ class UserObject extends FlexObject implements UserInterface, Countable
|
||||
use UserTrait;
|
||||
use UserObjectLegacyTrait;
|
||||
|
||||
/** @var Closure|null */
|
||||
static public $authorizeCallable;
|
||||
|
||||
/** @var array|null */
|
||||
protected $_uploads_original;
|
||||
/** @var FileInterface|null */
|
||||
@@ -259,6 +263,15 @@ class UserObject extends FlexObject implements UserInterface, Countable
|
||||
}
|
||||
}
|
||||
|
||||
$authorizeCallable = static::$authorizeCallable;
|
||||
if ($authorizeCallable instanceof Closure) {
|
||||
$authorizeCallable->bindTo($this);
|
||||
$authorized = $authorizeCallable($action, $scope);
|
||||
if (is_bool($authorized)) {
|
||||
return $authorized;
|
||||
}
|
||||
}
|
||||
|
||||
// Check user access.
|
||||
$access = $this->getAccess();
|
||||
$authorized = $access->authorize($action, $scope);
|
||||
|
||||
@@ -60,7 +60,7 @@ class GPM extends Iterator
|
||||
{
|
||||
parent::__construct();
|
||||
|
||||
Folder::create(GRAV_ROOT . '/cache/gpm');
|
||||
Folder::create(CACHE_DIR . '/gpm');
|
||||
|
||||
$this->cache = [];
|
||||
$this->installed = new Local\Packages();
|
||||
|
||||
@@ -20,11 +20,13 @@ use Grav\Common\Security;
|
||||
use Grav\Common\Utils;
|
||||
use Grav\Framework\Filesystem\Filesystem;
|
||||
use Grav\Framework\Form\FormFlashFile;
|
||||
use Grav\Framework\Mime\MimeTypes;
|
||||
use Psr\Http\Message\UploadedFileInterface;
|
||||
use RocketTheme\Toolbox\File\YamlFile;
|
||||
use RocketTheme\Toolbox\ResourceLocator\UniformResourceLocator;
|
||||
use RuntimeException;
|
||||
use function dirname;
|
||||
use function in_array;
|
||||
|
||||
/**
|
||||
* Implements media upload and delete functionality.
|
||||
@@ -179,16 +181,20 @@ trait MediaUploadTrait
|
||||
}
|
||||
}
|
||||
|
||||
$grav = Grav::instance();
|
||||
/** @var MimeTypes $mimeChecker */
|
||||
$mimeChecker = $grav['mime'];
|
||||
|
||||
// Handle Accepted file types. Accept can only be mime types (image/png | image/*) or file extensions (.pdf | .jpg)
|
||||
$accepted = false;
|
||||
$errors = [];
|
||||
// Do not trust mime type sent by the browser.
|
||||
$mime = Utils::getMimeByFilename($filename);
|
||||
$mimeTest = $metadata['mime'] ?? $mime;
|
||||
if ($mime !== $mimeTest) {
|
||||
$mime = $metadata['mime'] ?? $mimeChecker->getMimeType($extension);
|
||||
$validExtensions = $mimeChecker->getExtensions($mime);
|
||||
if (!in_array($extension, $validExtensions, true)) {
|
||||
throw new RuntimeException('The mime type does not match to file extension', 400);
|
||||
}
|
||||
|
||||
$accepted = false;
|
||||
$errors = [];
|
||||
foreach ((array)$settings['accept'] as $type) {
|
||||
// Force acceptance of any file when star notation
|
||||
if ($type === '*') {
|
||||
@@ -418,6 +424,17 @@ trait MediaUploadTrait
|
||||
$uploadedFile->moveTo($filepath);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get upload settings.
|
||||
*
|
||||
* @param array|null $settings Form field specific settings (override).
|
||||
* @return array
|
||||
*/
|
||||
public function getUploadSettings(?array $settings = null): array
|
||||
{
|
||||
return null !== $settings ? $settings + $this->_upload_defaults : $this->_upload_defaults;
|
||||
}
|
||||
|
||||
/**
|
||||
* Internal logic to copy file.
|
||||
*
|
||||
@@ -604,17 +621,6 @@ trait MediaUploadTrait
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get upload settings.
|
||||
*
|
||||
* @param array|null $settings Form field specific settings (override).
|
||||
* @return array
|
||||
*/
|
||||
protected function getUploadSettings(?array $settings = null): array
|
||||
{
|
||||
return null !== $settings ? $settings + $this->_upload_defaults : $this->_upload_defaults;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $filename
|
||||
* @param string $path
|
||||
|
||||
@@ -145,6 +145,18 @@ class Collection extends Iterator implements PageCollectionInterface
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set current page.
|
||||
*/
|
||||
public function setCurrent(string $path): void
|
||||
{
|
||||
reset($this->items);
|
||||
|
||||
while (($key = key($this->items)) !== null && $key !== $path) {
|
||||
next($this->items);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns current page.
|
||||
*
|
||||
|
||||
@@ -105,12 +105,12 @@ class InitializeProcessor extends ProcessorBase
|
||||
// TODO: remove in 2.0.
|
||||
$this->container['accounts'];
|
||||
|
||||
// Initialize session.
|
||||
$this->initializeSession($config);
|
||||
|
||||
// Initialize URI (uses session, see issue #3269).
|
||||
$this->initializeUri($config);
|
||||
|
||||
// Initialize session.
|
||||
$this->initializeSession($config);
|
||||
|
||||
// Grav may return redirect response right away.
|
||||
$redirectCode = (int)$config->get('system.pages.redirect_trailing_slash', 1);
|
||||
if ($redirectCode) {
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
namespace Grav\Common\Processors;
|
||||
|
||||
use Grav\Common\Page\Interfaces\PageInterface;
|
||||
use Grav\Plugin\Form\Forms;
|
||||
use RocketTheme\Toolbox\Event\Event;
|
||||
use Psr\Http\Message\ResponseInterface;
|
||||
use Psr\Http\Message\ServerRequestInterface;
|
||||
@@ -65,12 +66,18 @@ class PagesProcessor extends ProcessorBase
|
||||
|
||||
$task = $this->container['task'];
|
||||
$action = $this->container['action'];
|
||||
|
||||
/** @var Forms $forms */
|
||||
$forms = $this->container['forms'] ?? null;
|
||||
$form = $forms ? $forms->getActiveForm() : null;
|
||||
|
||||
$options = ['page' => $page, 'form' => $form, 'request' => $request];
|
||||
if ($task) {
|
||||
$event = new Event(['task' => $task, 'page' => $page]);
|
||||
$event = new Event(['task' => $task] + $options);
|
||||
$this->container->fireEvent('onPageTask', $event);
|
||||
$this->container->fireEvent('onPageTask.' . $task, $event);
|
||||
} elseif ($action) {
|
||||
$event = new Event(['action' => $action, 'page' => $page]);
|
||||
$event = new Event(['action' => $action] + $options);
|
||||
$this->container->fireEvent('onPageAction', $event);
|
||||
$this->container->fireEvent('onPageAction.' . $action, $event);
|
||||
}
|
||||
|
||||
@@ -17,6 +17,7 @@ use Grav\Common\Config\Config;
|
||||
use Grav\Common\Config\ConfigFileFinder;
|
||||
use Grav\Common\Config\Setup;
|
||||
use Grav\Common\Language\Language;
|
||||
use Grav\Framework\Mime\MimeTypes;
|
||||
use Pimple\Container;
|
||||
use Pimple\ServiceProviderInterface;
|
||||
use RocketTheme\Toolbox\File\YamlFile;
|
||||
@@ -56,6 +57,19 @@ class ConfigServiceProvider implements ServiceProviderInterface
|
||||
return $config;
|
||||
};
|
||||
|
||||
$container['mime'] = function ($c) {
|
||||
/** @var Config $config */
|
||||
$config = $c['config'];
|
||||
$mimes = $config->get('mime.types', []);
|
||||
foreach ($config->get('media.types', []) as $ext => $media) {
|
||||
if (!empty($media['mime'])) {
|
||||
$mimes[$ext] = array_unique(array_merge([$media['mime']], $mimes[$ext] ?? []));
|
||||
}
|
||||
}
|
||||
|
||||
return MimeTypes::createFromMimes($mimes);
|
||||
};
|
||||
|
||||
$container['languages'] = function ($c) {
|
||||
return static::languages($c);
|
||||
};
|
||||
|
||||
@@ -1499,7 +1499,7 @@ class GravExtension extends AbstractExtension implements GlobalsInterface
|
||||
}
|
||||
|
||||
//Look for existing class
|
||||
$svg = preg_replace_callback('/^<svg[^>]*(class=\")([^"]*)(\")[^>]*>/', function($matches) use ($classes, &$matched) {
|
||||
$svg = preg_replace_callback('/^<svg[^>]*(class=\"([^"]*)\")[^>]*>/', function($matches) use ($classes, &$matched) {
|
||||
if (isset($matches[2])) {
|
||||
$new_classes = $matches[2] . $classes;
|
||||
$matched = true;
|
||||
|
||||
@@ -49,16 +49,15 @@ class TwigNodeTryCatch extends Node
|
||||
|
||||
$compiler
|
||||
->indent()
|
||||
->subcompile($this->getNode('try'));
|
||||
->subcompile($this->getNode('try'))
|
||||
->outdent()
|
||||
->write('} catch (\Exception $e) {' . "\n")
|
||||
->indent()
|
||||
->write('if (isset($context[\'grav\'][\'debugger\'])) $context[\'grav\'][\'debugger\']->addException($e);' . "\n")
|
||||
->write('$context[\'e\'] = $e;' . "\n");
|
||||
|
||||
if ($this->hasNode('catch')) {
|
||||
$compiler
|
||||
->outdent()
|
||||
->write('} catch (\Exception $e) {' . "\n")
|
||||
->indent()
|
||||
->write('if (isset($context[\'grav\'][\'debugger\'])) $context[\'grav\'][\'debugger\']->addException($e);' . "\n")
|
||||
->write('$context[\'e\'] = $e;' . "\n")
|
||||
->subcompile($this->getNode('catch'));
|
||||
$compiler->subcompile($this->getNode('catch'));
|
||||
}
|
||||
|
||||
$compiler
|
||||
|
||||
@@ -239,9 +239,9 @@ class FlexDirectory implements FlexDirectoryInterface
|
||||
|
||||
// If configuration is found in main configuration, use it.
|
||||
if (str_starts_with($uri, 'config://')) {
|
||||
$path = strtr(substr($uri, 9, -5), '/', '.');
|
||||
$path = str_replace('/', '.', substr($uri, 9, -5));
|
||||
|
||||
return $grav['config']->get($path);
|
||||
return (array)$grav['config']->get($path);
|
||||
}
|
||||
|
||||
// Load the configuration file.
|
||||
@@ -831,7 +831,7 @@ class FlexDirectory implements FlexDirectoryInterface
|
||||
* @param array $call
|
||||
* @return void
|
||||
*/
|
||||
protected function dynamicFlexField(array &$field, $property, array $call)
|
||||
protected function dynamicFlexField(array &$field, $property, array $call): void
|
||||
{
|
||||
$params = (array)$call['params'];
|
||||
$object = $call['object'] ?? null;
|
||||
@@ -840,11 +840,28 @@ class FlexDirectory implements FlexDirectoryInterface
|
||||
if ($object && method_exists($object, $method)) {
|
||||
$value = $object->{$method}(...$params);
|
||||
if (is_array($value) && isset($field[$property]) && is_array($field[$property])) {
|
||||
$field[$property] = array_merge_recursive($field[$property], $value);
|
||||
$value = $this->mergeArrays($field[$property], $value);
|
||||
}
|
||||
$field[$property] = $value;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $array1
|
||||
* @param array $array2
|
||||
* @return array
|
||||
*/
|
||||
protected function mergeArrays(array $array1, array $array2): array
|
||||
{
|
||||
foreach ($array2 as $key => $value) {
|
||||
if (is_array($value) && isset($array1[$key]) && is_array($array1[$key])) {
|
||||
$array1[$key] = $this->mergeArrays($array1[$key], $value);
|
||||
} else {
|
||||
$field[$property] = $value;
|
||||
$array1[$key] = $value;
|
||||
}
|
||||
}
|
||||
|
||||
return $array1;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -453,7 +453,9 @@ class FlexDirectoryForm implements FlexDirectoryFormInterface, JsonSerializable
|
||||
protected function doSerialize(): array
|
||||
{
|
||||
return $this->doTraitSerialize() + [
|
||||
'form' => $this->form,
|
||||
'directory' => $this->directory,
|
||||
'flexName' => $this->flexName
|
||||
];
|
||||
}
|
||||
|
||||
@@ -465,7 +467,9 @@ class FlexDirectoryForm implements FlexDirectoryFormInterface, JsonSerializable
|
||||
{
|
||||
$this->doTraitUnserialize($data);
|
||||
|
||||
$this->form = $data['form'];
|
||||
$this->directory = $data['directory'];
|
||||
$this->flexName = $data['flexName'];
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -103,7 +103,14 @@ class FlexForm implements FlexObjectFormInterface, JsonSerializable
|
||||
{
|
||||
$this->name = $name;
|
||||
$this->setObject($object);
|
||||
$this->setName($object->getFlexType(), $name);
|
||||
|
||||
if (isset($options['form']['name'])) {
|
||||
// Use custom form name.
|
||||
$this->flexName = $options['form']['name'];
|
||||
} else {
|
||||
// Use standard form name.
|
||||
$this->setName($object->getFlexType(), $name);
|
||||
}
|
||||
$this->setId($this->getName());
|
||||
|
||||
$uniqueId = $options['unique_id'] ?? null;
|
||||
@@ -536,7 +543,11 @@ class FlexForm implements FlexObjectFormInterface, JsonSerializable
|
||||
protected function doSerialize(): array
|
||||
{
|
||||
return $this->doTraitSerialize() + [
|
||||
'items' => $this->items,
|
||||
'form' => $this->form,
|
||||
'object' => $this->object,
|
||||
'flexName' => $this->flexName,
|
||||
'submitMethod' => $this->submitMethod,
|
||||
];
|
||||
}
|
||||
|
||||
@@ -548,7 +559,11 @@ class FlexForm implements FlexObjectFormInterface, JsonSerializable
|
||||
{
|
||||
$this->doTraitUnserialize($data);
|
||||
|
||||
$this->object = $data['object'];
|
||||
$this->items = $data['items'] ?? null;
|
||||
$this->form = $data['form'] ?? null;
|
||||
$this->object = $data['object'] ?? null;
|
||||
$this->flexName = $data['flexName'] ?? null;
|
||||
$this->submitMethod = $data['submitMethod'] ?? null;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -44,6 +44,7 @@ use function is_array;
|
||||
use function is_object;
|
||||
use function is_scalar;
|
||||
use function is_string;
|
||||
use function json_encode;
|
||||
|
||||
/**
|
||||
* Class FlexObject
|
||||
@@ -820,11 +821,12 @@ class FlexObject implements FlexObjectInterface, FlexAuthorizeInterface
|
||||
*/
|
||||
public function getForm(string $name = '', array $options = null)
|
||||
{
|
||||
if (!isset($this->_forms[$name])) {
|
||||
$this->_forms[$name] = $this->createFormObject($name, $options);
|
||||
$hash = $name . '-' . md5(json_encode($options, JSON_THROW_ON_ERROR));
|
||||
if (!isset($this->_forms[$hash])) {
|
||||
$this->_forms[$hash] = $this->createFormObject($name, $options);
|
||||
}
|
||||
|
||||
return $this->_forms[$name];
|
||||
return $this->_forms[$hash];
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -40,6 +40,8 @@ class FolderStorage extends AbstractFilesystemStorage
|
||||
protected $dataFolder;
|
||||
/** @var string Pattern to access an object. */
|
||||
protected $dataPattern = '{FOLDER}/{KEY}/{FILE}{EXT}';
|
||||
/** @var string[] */
|
||||
protected $variables = ['FOLDER' => '%1$s', 'KEY' => '%2$s', 'KEY:2' => '%3$s', 'FILE' => '%4$s', 'EXT' => '%5$s'];
|
||||
/** @var string Filename for the object. */
|
||||
protected $dataFile;
|
||||
/** @var string File extension for the object. */
|
||||
@@ -380,6 +382,12 @@ class FolderStorage extends AbstractFilesystemStorage
|
||||
if (isset($data[0])) {
|
||||
throw new RuntimeException('Broken object file');
|
||||
}
|
||||
|
||||
// Add key field to the object.
|
||||
$keyField = $this->keyField;
|
||||
if ($keyField !== 'storage_key' && !isset($data[$keyField])) {
|
||||
$data[$keyField] = $key;
|
||||
}
|
||||
} catch (RuntimeException $e) {
|
||||
$data = ['__ERROR' => $e->getMessage()];
|
||||
} finally {
|
||||
@@ -692,9 +700,7 @@ class FolderStorage extends AbstractFilesystemStorage
|
||||
$this->keyLen = (int)($options['key_len'] ?? 32);
|
||||
$this->caseSensitive = (bool)($options['case_sensitive'] ?? true);
|
||||
|
||||
$variables = ['FOLDER' => '%1$s', 'KEY' => '%2$s', 'KEY:2' => '%3$s', 'FILE' => '%4$s', 'EXT' => '%5$s'];
|
||||
$pattern = Utils::simpleTemplate($pattern, $variables);
|
||||
|
||||
$pattern = Utils::simpleTemplate($pattern, $this->variables);
|
||||
if (!$pattern) {
|
||||
throw new RuntimeException('Bad storage folder pattern');
|
||||
}
|
||||
|
||||
@@ -120,7 +120,7 @@ trait FlexMediaTrait
|
||||
// Load settings for the field.
|
||||
$schema = $this->getBlueprint()->schema();
|
||||
$settings = $field && is_object($schema) ? (array)$schema->getProperty($field) : null;
|
||||
if (!isset($settings) || !is_array($settings)) {
|
||||
if (!is_array($settings)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
107
system/src/Grav/Framework/Mime/MimeTypes.php
Normal file
107
system/src/Grav/Framework/Mime/MimeTypes.php
Normal file
@@ -0,0 +1,107 @@
|
||||
<?php declare(strict_types=1);
|
||||
|
||||
/**
|
||||
* @package Grav\Framework\Mime
|
||||
*
|
||||
* @copyright Copyright (c) 2015 - 2021 Trilby Media, LLC. All rights reserved.
|
||||
* @license MIT License; see LICENSE file for details.
|
||||
*/
|
||||
|
||||
namespace Grav\Framework\Mime;
|
||||
|
||||
use function in_array;
|
||||
|
||||
/**
|
||||
* Class to handle mime-types.
|
||||
*/
|
||||
class MimeTypes
|
||||
{
|
||||
/** @var array */
|
||||
protected $extensions;
|
||||
/** @var array */
|
||||
protected $mimes;
|
||||
|
||||
/**
|
||||
* Create a new mime types instance with the given mappings.
|
||||
*
|
||||
* @param array $mimes An associative array containing ['ext' => ['mime/type', 'mime/type2']]
|
||||
*/
|
||||
public static function createFromMimes(array $mimes): self
|
||||
{
|
||||
$extensions = [];
|
||||
foreach ($mimes as $ext => $list) {
|
||||
foreach ($list as $mime) {
|
||||
$list = $extensions[$mime] ?? [];
|
||||
if (!in_array($ext, $list, true)) {
|
||||
$list[] = $ext;
|
||||
$extensions[$mime] = $list;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return new static($extensions, $mimes);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $extension
|
||||
* @return string|null
|
||||
*/
|
||||
public function getMimeType(string $extension): ?string
|
||||
{
|
||||
$extension = $this->cleanInput($extension);
|
||||
|
||||
return $this->mimes[$extension][0] ?? null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $mime
|
||||
* @return string|null
|
||||
*/
|
||||
public function getExtension(string $mime): ?string
|
||||
{
|
||||
$mime = $this->cleanInput($mime);
|
||||
|
||||
return $this->extensions[$mime][0] ?? null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $extension
|
||||
* @return array
|
||||
*/
|
||||
public function getMimeTypes(string $extension): array
|
||||
{
|
||||
$extension = $this->cleanInput($extension);
|
||||
|
||||
return $this->mimes[$extension] ?? [];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $mime
|
||||
* @return array
|
||||
*/
|
||||
public function getExtensions(string $mime): array
|
||||
{
|
||||
$mime = $this->cleanInput($mime);
|
||||
|
||||
return $this->extensions[$mime] ?? [];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $input
|
||||
* @return string
|
||||
*/
|
||||
protected function cleanInput(string $input): string
|
||||
{
|
||||
return strtolower(trim($input));
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $extensions
|
||||
* @param array $mimes
|
||||
*/
|
||||
protected function __construct(array $extensions, array $mimes)
|
||||
{
|
||||
$this->extensions = $extensions;
|
||||
$this->mimes = $mimes;
|
||||
}
|
||||
}
|
||||
@@ -23,6 +23,9 @@ class UploadedFile implements UploadedFileInterface
|
||||
{
|
||||
use UploadedFileDecoratorTrait;
|
||||
|
||||
/** @var array */
|
||||
private $meta = [];
|
||||
|
||||
/**
|
||||
* @param StreamInterface|string|resource $streamOrFile
|
||||
* @param int $size
|
||||
@@ -34,4 +37,34 @@ class UploadedFile implements UploadedFileInterface
|
||||
{
|
||||
$this->uploadedFile = new \Nyholm\Psr7\UploadedFile($streamOrFile, $size, $errorStatus, $clientFilename, $clientMediaType);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $meta
|
||||
* @return $this
|
||||
*/
|
||||
public function setMeta(array $meta)
|
||||
{
|
||||
$this->meta = $meta;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $meta
|
||||
* @return $this
|
||||
*/
|
||||
public function addMeta(array $meta)
|
||||
{
|
||||
$this->meta = array_merge($this->meta, $meta);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
public function getMeta(): array
|
||||
{
|
||||
return $this->meta;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user