test appel img twig
This commit is contained in:
@@ -10,6 +10,7 @@
|
||||
namespace Grav\Common\Assets;
|
||||
|
||||
use Grav\Common\Assets\Traits\AssetUtilsTrait;
|
||||
use Grav\Common\Config\Config;
|
||||
use Grav\Common\Grav;
|
||||
use Grav\Common\Uri;
|
||||
use Grav\Common\Utils;
|
||||
@@ -171,6 +172,31 @@ abstract class BaseAsset extends PropertyObject
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Receive asset location and return the SRI integrity hash
|
||||
*
|
||||
* @param $input
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function integrityHash( $input )
|
||||
{
|
||||
$grav = Grav::instance();
|
||||
|
||||
$assetsConfig = $grav['config']->get('system.assets');
|
||||
|
||||
if ( !empty($assetsConfig['enable_asset_sri']) && $assetsConfig['enable_asset_sri'] )
|
||||
{
|
||||
$dataToHash = file_get_contents( GRAV_ROOT . $input);
|
||||
|
||||
$hash = hash('sha256', $dataToHash, true);
|
||||
$hash_base64 = base64_encode($hash);
|
||||
return ' integrity="sha256-' . $hash_base64 . '"';
|
||||
}
|
||||
|
||||
return '';
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
|
||||
@@ -47,6 +47,6 @@ class Css extends BaseAsset
|
||||
return "<style>\n" . trim($buffer) . "\n</style>\n";
|
||||
}
|
||||
|
||||
return '<link href="' . trim($this->asset) . $this->renderQueryString() . '"' . $this->renderAttributes() . ">\n";
|
||||
return '<link href="' . trim($this->asset) . $this->renderQueryString() . '"' . $this->renderAttributes() . $this->integrityHash($this->asset) . ">\n";
|
||||
}
|
||||
}
|
||||
|
||||
@@ -43,6 +43,6 @@ class Js extends BaseAsset
|
||||
return '<script' . $this->renderAttributes() . ">\n" . trim($buffer) . "\n</script>\n";
|
||||
}
|
||||
|
||||
return '<script src="' . trim($this->asset) . $this->renderQueryString() . '"' . $this->renderAttributes() . "></script>\n";
|
||||
return '<script src="' . trim($this->asset) . $this->renderQueryString() . '"' . $this->renderAttributes() . $this->integrityHash($this->asset) . "></script>\n";
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
|
||||
namespace Grav\Common\Assets;
|
||||
|
||||
use Grav\Common\Assets\BaseAsset;
|
||||
use Grav\Common\Assets\Traits\AssetUtilsTrait;
|
||||
use Grav\Common\Config\Config;
|
||||
use Grav\Common\Grav;
|
||||
@@ -148,7 +149,7 @@ class Pipeline extends PropertyObject
|
||||
$output = "<style>\n" . $buffer . "\n</style>\n";
|
||||
} else {
|
||||
$this->asset = $relative_path;
|
||||
$output = '<link href="' . $relative_path . $this->renderQueryString() . '"' . $this->renderAttributes() . ">\n";
|
||||
$output = '<link href="' . $relative_path . $this->renderQueryString() . '"' . $this->renderAttributes() . BaseAsset::integrityHash($this->asset) . ">\n";
|
||||
}
|
||||
|
||||
return $output;
|
||||
@@ -211,7 +212,7 @@ class Pipeline extends PropertyObject
|
||||
$output = '<script' . $this->renderAttributes(). ">\n" . $buffer . "\n</script>\n";
|
||||
} else {
|
||||
$this->asset = $relative_path;
|
||||
$output = '<script src="' . $relative_path . $this->renderQueryString() . '"' . $this->renderAttributes() . "></script>\n";
|
||||
$output = '<script src="' . $relative_path . $this->renderQueryString() . '"' . $this->renderAttributes() . BaseAsset::integrityHash($this->asset) . "></script>\n";
|
||||
}
|
||||
|
||||
return $output;
|
||||
|
||||
@@ -71,6 +71,7 @@ class Cache extends Getters
|
||||
'cache://twig/',
|
||||
'cache://doctrine/',
|
||||
'cache://compiled/',
|
||||
'cache://clockwork/',
|
||||
'cache://validated-',
|
||||
'cache://images',
|
||||
'asset://',
|
||||
@@ -80,6 +81,7 @@ class Cache extends Getters
|
||||
'cache://twig/',
|
||||
'cache://doctrine/',
|
||||
'cache://compiled/',
|
||||
'cache://clockwork/',
|
||||
'cache://validated-',
|
||||
'asset://',
|
||||
];
|
||||
@@ -311,7 +313,7 @@ class Cache extends Getters
|
||||
if ($password && !$redis->auth($password)) {
|
||||
throw new \RedisException('Redis authentication failed');
|
||||
}
|
||||
|
||||
|
||||
// Select alternate ( !=0 ) database ID if set
|
||||
if ($databaseId && !$redis->select($databaseId)) {
|
||||
throw new \RedisException('Could not select alternate Redis database ID');
|
||||
@@ -498,7 +500,7 @@ class Cache extends Getters
|
||||
$anything = true;
|
||||
}
|
||||
} elseif (is_dir($file)) {
|
||||
if (Folder::delete($file)) {
|
||||
if (Folder::delete($file, false)) {
|
||||
$anything = true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -21,13 +21,16 @@ use Grav\Common\Grav;
|
||||
use Grav\Common\Page\Header;
|
||||
use Grav\Common\Page\Interfaces\PageCollectionInterface;
|
||||
use Grav\Common\Page\Interfaces\PageInterface;
|
||||
use Grav\Common\User\Interfaces\UserInterface;
|
||||
use Grav\Common\Utils;
|
||||
use Grav\Framework\Flex\FlexDirectory;
|
||||
use Grav\Framework\Flex\Interfaces\FlexCollectionInterface;
|
||||
use Grav\Framework\Flex\Interfaces\FlexStorageInterface;
|
||||
use Grav\Framework\Flex\Pages\FlexPageIndex;
|
||||
use InvalidArgumentException;
|
||||
use RuntimeException;
|
||||
use function array_slice;
|
||||
use function count;
|
||||
use function in_array;
|
||||
use function is_array;
|
||||
use function is_string;
|
||||
|
||||
@@ -299,7 +302,33 @@ class PageIndex extends FlexPageIndex implements PageCollectionInterface
|
||||
'type' => ['root', 'dir'],
|
||||
];
|
||||
|
||||
return $this->getLevelListingRecurse($options);
|
||||
$key = 'page.idx.lev.' . sha1(json_encode($options, JSON_THROW_ON_ERROR) . $this->getCacheKey());
|
||||
$checksum = $this->getCacheChecksum();
|
||||
|
||||
$cache = $this->getCache('object');
|
||||
|
||||
/** @var Debugger $debugger */
|
||||
$debugger = Grav::instance()['debugger'];
|
||||
|
||||
$result = null;
|
||||
try {
|
||||
$cached = $cache->get($key);
|
||||
$test = $cached[0] ?? null;
|
||||
$result = $test === $checksum ? ($cached[1] ?? null) : null;
|
||||
} catch (\Psr\SimpleCache\InvalidArgumentException $e) {
|
||||
$debugger->addException($e);
|
||||
}
|
||||
|
||||
try {
|
||||
if (null === $result) {
|
||||
$result = $this->getLevelListingRecurse($options);
|
||||
$cache->set($key, [$checksum, $result]);
|
||||
}
|
||||
} catch (\Psr\SimpleCache\InvalidArgumentException $e) {
|
||||
$debugger->addException($e);
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -429,6 +458,9 @@ class PageIndex extends FlexPageIndex implements PageCollectionInterface
|
||||
$selectedChildren = $selectedChildren->order($sortby, $order, $custom ?? null);
|
||||
}
|
||||
|
||||
/** @var UserInterface|null $user */
|
||||
$user = Grav::instance()['user'] ?? null;
|
||||
|
||||
/** @var PageObject $child */
|
||||
foreach ($selectedChildren as $child) {
|
||||
$selected = $child->path() === $extra;
|
||||
@@ -482,7 +514,7 @@ class PageIndex extends FlexPageIndex implements PageCollectionInterface
|
||||
'visible' => $child->visible(),
|
||||
'routable' => $child->routable(),
|
||||
'tags' => $tags,
|
||||
'actions' => $this->getListingActions($child),
|
||||
'actions' => $this->getListingActions($child, $user),
|
||||
];
|
||||
$extras = array_filter($extras, static function ($v) {
|
||||
return $v !== null;
|
||||
@@ -535,20 +567,21 @@ class PageIndex extends FlexPageIndex implements PageCollectionInterface
|
||||
|
||||
/**
|
||||
* @param PageObject $object
|
||||
* @param UserInterface $user
|
||||
* @return array
|
||||
*/
|
||||
protected function getListingActions(PageObject $object): array
|
||||
protected function getListingActions(PageObject $object, UserInterface $user): array
|
||||
{
|
||||
$actions = [];
|
||||
if ($object->isAuthorized('read')) {
|
||||
if ($object->isAuthorized('read', null, $user)) {
|
||||
$actions[] = 'preview';
|
||||
$actions[] = 'edit';
|
||||
}
|
||||
if ($object->isAuthorized('update')) {
|
||||
if ($object->isAuthorized('update', null, $user)) {
|
||||
$actions[] = 'copy';
|
||||
$actions[] = 'move';
|
||||
}
|
||||
if ($object->isAuthorized('delete')) {
|
||||
if ($object->isAuthorized('delete', null, $user)) {
|
||||
$actions[] = 'delete';
|
||||
}
|
||||
|
||||
|
||||
@@ -62,7 +62,6 @@ class PageObject extends FlexPageObject
|
||||
|
||||
/** @var string Language code, eg: 'en' */
|
||||
protected $language;
|
||||
|
||||
/** @var string File format, eg. 'md' */
|
||||
protected $format;
|
||||
|
||||
@@ -78,6 +77,7 @@ class PageObject extends FlexPageObject
|
||||
'path' => true,
|
||||
'full_order' => true,
|
||||
'filterBy' => true,
|
||||
'translated' => false,
|
||||
] + parent::getCachedMethods();
|
||||
}
|
||||
|
||||
@@ -92,6 +92,11 @@ class PageObject extends FlexPageObject
|
||||
}
|
||||
}
|
||||
|
||||
public function translated(): bool
|
||||
{
|
||||
return $this->translatedLanguages(true) ? true : false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string|array $query
|
||||
* @return Route|null
|
||||
@@ -223,7 +228,7 @@ class PageObject extends FlexPageObject
|
||||
}
|
||||
|
||||
// Reorder siblings.
|
||||
$siblings = is_array($reorder) ? $this->reorderSiblings($reorder) : [];
|
||||
$siblings = is_array($reorder) ? ($this->reorderSiblings($reorder) ?? []) : [];
|
||||
|
||||
$data = $this->prepareStorage();
|
||||
unset($data['header']);
|
||||
@@ -289,6 +294,9 @@ class PageObject extends FlexPageObject
|
||||
$grav->fireEvent('onAdminAfterSave', new Event(['type' => 'flex', 'directory' => $this->getFlexDirectory(), 'object' => $this]));
|
||||
}
|
||||
|
||||
// Reset original after save events have all been called.
|
||||
$this->_original = null;
|
||||
|
||||
return $instance;
|
||||
}
|
||||
|
||||
@@ -308,13 +316,14 @@ class PageObject extends FlexPageObject
|
||||
|
||||
$this->_reorder = [];
|
||||
$this->setProperty('parent_key', $parent->getStorageKey());
|
||||
$this->storeOriginal();
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $ordering
|
||||
* @return PageCollection
|
||||
* @return PageCollection|null
|
||||
*/
|
||||
protected function reorderSiblings(array $ordering)
|
||||
{
|
||||
@@ -324,17 +333,35 @@ class PageObject extends FlexPageObject
|
||||
$newParentKey = $this->getProperty('parent_key');
|
||||
$isMoved = $oldParentKey !== $newParentKey;
|
||||
$order = !$isMoved ? $this->order() : false;
|
||||
if ($order !== false) {
|
||||
$order = (int)$order;
|
||||
}
|
||||
|
||||
$parent = $this->parent();
|
||||
if (!$parent) {
|
||||
throw new RuntimeException('Cannot reorder a page which has no parent');
|
||||
}
|
||||
|
||||
/** @var PageCollection|null $siblings */
|
||||
/** @var PageCollection $siblings */
|
||||
$siblings = $parent->children();
|
||||
$siblings = $siblings->getCollection()->withOrdered();
|
||||
|
||||
/** @var PageCollection|null $siblings */
|
||||
$siblings = $siblings->getCollection()->withOrdered()->orderBy(['order' => 'ASC']);
|
||||
// Handle special case where ordering isn't given.
|
||||
if ($ordering === []) {
|
||||
if ($order >= 999999) {
|
||||
// Set ordering to point to be the last item.
|
||||
$order = 0;
|
||||
foreach ($siblings as $sibling) {
|
||||
$order = max($order, (int)$sibling->order());
|
||||
}
|
||||
$this->order($order + 1);
|
||||
}
|
||||
|
||||
// Do not change sibling ordering.
|
||||
return null;
|
||||
}
|
||||
|
||||
$siblings = $siblings->orderBy(['order' => 'ASC']);
|
||||
|
||||
if ($storageKey !== null) {
|
||||
if ($order !== false) {
|
||||
@@ -378,7 +405,9 @@ class PageObject extends FlexPageObject
|
||||
throw new RuntimeException("New parent page '{$parentKey}' not found.");
|
||||
}
|
||||
}
|
||||
$newSiblings = $newParent->children()->getCollection()->withOrdered();
|
||||
/** @var PageCollection $newSiblings */
|
||||
$newSiblings = $newParent->children();
|
||||
$newSiblings = $newSiblings->getCollection()->withOrdered();
|
||||
$order = 0;
|
||||
foreach ($newSiblings as $sibling) {
|
||||
$order = max($order, (int)$sibling->order());
|
||||
@@ -584,14 +613,17 @@ class PageObject extends FlexPageObject
|
||||
unset($elements['ordering'], $elements['order']);
|
||||
} elseif (array_key_exists('ordering', $elements) && array_key_exists('order', $elements)) {
|
||||
// Store ordering.
|
||||
$this->_reorder = !empty($elements['order']) ? explode(',', $elements['order']) : [];
|
||||
$ordering = $elements['order'] ?? null;
|
||||
$this->_reorder = !empty($ordering) ? explode(',', $ordering) : [];
|
||||
|
||||
$order = false;
|
||||
if ((bool)($elements['ordering'] ?? false)) {
|
||||
$order = 999999;
|
||||
$order = $this->order();
|
||||
if ($order === false) {
|
||||
$order = 999999;
|
||||
}
|
||||
}
|
||||
|
||||
$this->order();
|
||||
$elements['order'] = $order;
|
||||
}
|
||||
|
||||
|
||||
@@ -110,6 +110,9 @@ class PageStorage extends FolderStorage
|
||||
}
|
||||
} catch (RuntimeException $e) {
|
||||
$frontmatter = 'ERROR: ' . $e->getMessage();
|
||||
} finally {
|
||||
$file->free();
|
||||
unset($file);
|
||||
}
|
||||
|
||||
return $frontmatter;
|
||||
@@ -127,6 +130,9 @@ class PageStorage extends FolderStorage
|
||||
$raw = $file->raw();
|
||||
} catch (RuntimeException $e) {
|
||||
$raw = 'ERROR: ' . $e->getMessage();
|
||||
} finally {
|
||||
$file->free();
|
||||
unset($file);
|
||||
}
|
||||
|
||||
return $raw;
|
||||
@@ -407,7 +413,7 @@ class PageStorage extends FolderStorage
|
||||
if (!$isClone && $file->exists()) {
|
||||
/** @var UniformResourceLocator $locator */
|
||||
$locator = $grav['locator'];
|
||||
$toPath = $locator->isStream($newFilepath) ? $locator->findResource($newFilepath, true, true) : $newFilepath;
|
||||
$toPath = $locator->isStream($newFilepath) ? $locator->findResource($newFilepath, true, true) : GRAV_ROOT . "/{$newFilepath}";
|
||||
$success = $file->rename($toPath);
|
||||
if (!$success) {
|
||||
throw new RuntimeException("Changing page template failed: {$oldFilepath} => {$newFilepath}");
|
||||
@@ -439,16 +445,19 @@ class PageStorage extends FolderStorage
|
||||
} else {
|
||||
$debugger->addMessage('Page content has not been changed, do not update the file', 'debug');
|
||||
}
|
||||
|
||||
/** @var UniformResourceLocator $locator */
|
||||
$locator = Grav::instance()['locator'];
|
||||
if ($locator->isStream($newFolder)) {
|
||||
$locator->clearCache();
|
||||
}
|
||||
} catch (RuntimeException $e) {
|
||||
$name = isset($file) ? $file->filename() : $newKey;
|
||||
|
||||
throw new RuntimeException(sprintf('Flex saveRow(%s): %s', $name, $e->getMessage()));
|
||||
} finally {
|
||||
/** @var UniformResourceLocator $locator */
|
||||
$locator = Grav::instance()['locator'];
|
||||
$locator->clearCache();
|
||||
|
||||
if (isset($file)) {
|
||||
$file->free();
|
||||
unset($file);
|
||||
}
|
||||
}
|
||||
|
||||
$row['__META'] = $this->getObjectMeta($newKey, true);
|
||||
@@ -512,7 +521,11 @@ class PageStorage extends FolderStorage
|
||||
$locator = Grav::instance()['locator'];
|
||||
if (mb_strpos($key, '@@') === false) {
|
||||
$path = $this->getStoragePath($key);
|
||||
$path = $path ? $locator->findResource($path) : null;
|
||||
if (is_string($path)) {
|
||||
$path = $locator->isStream($path) ? $locator->findResource($path) : GRAV_ROOT . "/{$path}";
|
||||
} else {
|
||||
$path = null;
|
||||
}
|
||||
} else {
|
||||
$path = null;
|
||||
}
|
||||
|
||||
@@ -67,7 +67,7 @@ trait PageTranslateTrait
|
||||
if (!$folder) {
|
||||
return [];
|
||||
}
|
||||
$folder = $locator($folder);
|
||||
$folder = $locator->isStream($folder) ? $locator->getResource($folder) : GRAV_ROOT . "/{$folder}";
|
||||
|
||||
$list = array_fill_keys($languages, null);
|
||||
foreach ($translated as $languageCode => $languageFile) {
|
||||
|
||||
@@ -426,12 +426,18 @@ class Grav extends Container
|
||||
// Clean route for redirect
|
||||
$route = preg_replace("#^\/[\\\/]+\/#", '/', $route);
|
||||
|
||||
// Check for code in route
|
||||
$regex = '/.*(\[(30[1-7])\])$/';
|
||||
preg_match($regex, $route, $matches);
|
||||
if ($matches) {
|
||||
$route = str_replace($matches[1], '', $matches[0]);
|
||||
$code = $matches[2];
|
||||
if (null !== $code || $code < 300 || $code > 399) {
|
||||
$code = null;
|
||||
}
|
||||
|
||||
if (null === $code) {
|
||||
// Check for redirect code in the route: e.g. /new/[301], /new[301]/route or /new[301].html
|
||||
$regex = '/.*(\[(30[1-7])\])(.\w+|\/.*?)?$/';
|
||||
preg_match($regex, $route, $matches);
|
||||
if ($matches) {
|
||||
$route = str_replace($matches[1], '', $matches[0]);
|
||||
$code = $matches[2];
|
||||
}
|
||||
}
|
||||
|
||||
if ($code === null) {
|
||||
|
||||
@@ -34,7 +34,7 @@ class LogViewer
|
||||
public function objectTail($filepath, $lines = 1, $desc = true)
|
||||
{
|
||||
$data = $this->tail($filepath, $lines);
|
||||
$tailed_log = explode(PHP_EOL, $data);
|
||||
$tailed_log = $data ? explode(PHP_EOL, $data) : [];
|
||||
$line_objects = [];
|
||||
|
||||
foreach ($tailed_log as $line) {
|
||||
@@ -54,13 +54,13 @@ class LogViewer
|
||||
public function tail($filepath, $lines = 1)
|
||||
{
|
||||
|
||||
$f = @fopen($filepath, "rb");
|
||||
$f = $filepath ? @fopen($filepath, 'rb') : false;
|
||||
if ($f === false) {
|
||||
return false;
|
||||
} else {
|
||||
$buffer = ($lines < 2 ? 64 : ($lines < 10 ? 512 : 4096));
|
||||
}
|
||||
|
||||
$buffer = ($lines < 2 ? 64 : ($lines < 10 ? 512 : 4096));
|
||||
|
||||
fseek($f, -1, SEEK_END);
|
||||
if (fread($f, 1) != "\n") {
|
||||
$lines -= 1;
|
||||
|
||||
@@ -63,7 +63,7 @@ interface PageRoutableInterface
|
||||
* the parents route and the current Page's slug.
|
||||
*
|
||||
* @param string|null $var Set new default route.
|
||||
* @return string The route for the Page.
|
||||
* @return string|null The route for the Page.
|
||||
*/
|
||||
public function route($var = null);
|
||||
|
||||
|
||||
@@ -278,10 +278,10 @@ class Excerpts
|
||||
);
|
||||
}
|
||||
|
||||
$defaults = $config['images']['defaults'] ?? [];
|
||||
$defaults = $this->config['images']['defaults'] ?? [];
|
||||
if (count($defaults)) {
|
||||
foreach ($defaults as $method => $params) {
|
||||
if (!array_search($method, array_column($actions, 'method'))) {
|
||||
if (array_search($method, array_column($actions, 'method')) === false) {
|
||||
$actions[] = [
|
||||
'method' => $method,
|
||||
'params' => $params,
|
||||
|
||||
@@ -1875,7 +1875,7 @@ class Page implements PageInterface
|
||||
* the parents route and the current Page's slug.
|
||||
*
|
||||
* @param string|null $var Set new default route.
|
||||
* @return string The route for the Page.
|
||||
* @return string|null The route for the Page.
|
||||
*/
|
||||
public function route($var = null)
|
||||
{
|
||||
|
||||
@@ -769,6 +769,9 @@ class Pages
|
||||
public function get($path)
|
||||
{
|
||||
$path = (string)$path;
|
||||
if ($path === '') {
|
||||
return null;
|
||||
}
|
||||
|
||||
// Check for local instances first.
|
||||
if (array_key_exists($path, $this->instances)) {
|
||||
@@ -777,14 +780,26 @@ class Pages
|
||||
|
||||
$instance = $this->index[$path] ?? null;
|
||||
if (is_string($instance)) {
|
||||
/** @var Language $language */
|
||||
$language = $this->grav['language'];
|
||||
$lang = $language->getActive();
|
||||
if ($lang) {
|
||||
$instance .= ':' . $lang;
|
||||
if ($this->directory) {
|
||||
/** @var Language $language */
|
||||
$language = $this->grav['language'];
|
||||
$lang = $language->getActive();
|
||||
if ($lang) {
|
||||
$languages = $language->getFallbackLanguages($lang, true);
|
||||
$key = $instance;
|
||||
$instance = null;
|
||||
foreach ($languages as $code) {
|
||||
$test = $code ? $key . ':' . $code : $key;
|
||||
if (($instance = $this->directory->getObject($test, 'flex_key')) !== null) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
$instance = $this->directory->getObject($instance, 'flex_key');
|
||||
}
|
||||
}
|
||||
$instance = $this->directory ? $this->directory->getObject($instance, 'flex_key') : null;
|
||||
if ($instance) {
|
||||
|
||||
if ($instance instanceof PageInterface) {
|
||||
if ($this->fire_events && method_exists($instance, 'initialize')) {
|
||||
$instance->initialize();
|
||||
}
|
||||
@@ -1159,7 +1174,14 @@ class Pages
|
||||
$event->types = $types;
|
||||
$grav->fireEvent('onGetPageBlueprints', $event);
|
||||
|
||||
$types->scanBlueprints('theme://blueprints/');
|
||||
$types->init();
|
||||
|
||||
// Try new location first.
|
||||
$lookup = 'theme://blueprints/pages/';
|
||||
if (!is_dir($lookup)) {
|
||||
$lookup = 'theme://blueprints/';
|
||||
}
|
||||
$types->scanBlueprints($lookup);
|
||||
|
||||
// Scan templates
|
||||
$event = new Event();
|
||||
|
||||
@@ -32,22 +32,23 @@ class Types implements \ArrayAccess, \Iterator, \Countable
|
||||
/** @var array */
|
||||
protected $items;
|
||||
/** @var array */
|
||||
protected $systemBlueprints;
|
||||
protected $systemBlueprints = [];
|
||||
|
||||
/**
|
||||
* @param string $type
|
||||
* @param Blueprint|null $blueprint
|
||||
* @return void
|
||||
*/
|
||||
public function register($type, $blueprint = null)
|
||||
{
|
||||
if (!isset($this->items[$type])) {
|
||||
$this->items[$type] = [];
|
||||
} elseif (!$blueprint) {
|
||||
} elseif (null === $blueprint) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!$blueprint && $this->systemBlueprints) {
|
||||
$blueprint = $this->systemBlueprints[$type] ?? $this->systemBlueprints['default'];
|
||||
if (null === $blueprint) {
|
||||
$blueprint = $this->systemBlueprints[$type] ?? $this->systemBlueprints['default'] ?? null;
|
||||
}
|
||||
|
||||
if ($blueprint) {
|
||||
@@ -55,8 +56,23 @@ class Types implements \ArrayAccess, \Iterator, \Countable
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return void
|
||||
*/
|
||||
public function init()
|
||||
{
|
||||
if (null === $this->systemBlueprints) {
|
||||
// Register all blueprints from the blueprints stream.
|
||||
$this->systemBlueprints = $this->findBlueprints('blueprints://pages');
|
||||
foreach ($this->systemBlueprints as $type => $blueprint) {
|
||||
$this->register($type);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $uri
|
||||
* @return void
|
||||
*/
|
||||
public function scanBlueprints($uri)
|
||||
{
|
||||
@@ -64,15 +80,6 @@ class Types implements \ArrayAccess, \Iterator, \Countable
|
||||
throw new InvalidArgumentException('First parameter must be URI');
|
||||
}
|
||||
|
||||
if (null === $this->systemBlueprints) {
|
||||
$this->systemBlueprints = $this->findBlueprints('blueprints://pages');
|
||||
|
||||
// Register default by default.
|
||||
$this->register('default');
|
||||
|
||||
$this->register('external');
|
||||
}
|
||||
|
||||
foreach ($this->findBlueprints($uri) as $type => $blueprint) {
|
||||
$this->register($type, $blueprint);
|
||||
}
|
||||
@@ -80,6 +87,7 @@ class Types implements \ArrayAccess, \Iterator, \Countable
|
||||
|
||||
/**
|
||||
* @param string $uri
|
||||
* @return void
|
||||
*/
|
||||
public function scanTemplates($uri)
|
||||
{
|
||||
|
||||
@@ -16,6 +16,7 @@ use Grav\Common\Page\Interfaces\PageInterface;
|
||||
use Grav\Common\Config\Config;
|
||||
use LogicException;
|
||||
use RocketTheme\Toolbox\File\YamlFile;
|
||||
use RocketTheme\Toolbox\ResourceLocator\UniformResourceLocator;
|
||||
use Symfony\Component\EventDispatcher\EventDispatcher;
|
||||
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
|
||||
use function defined;
|
||||
@@ -35,11 +36,11 @@ class Plugin implements EventSubscriberInterface, ArrayAccess
|
||||
|
||||
/** @var Grav */
|
||||
protected $grav;
|
||||
/** @var Config */
|
||||
/** @var Config|null */
|
||||
protected $config;
|
||||
/** @var bool */
|
||||
protected $active = true;
|
||||
/** @var Blueprint */
|
||||
/** @var Blueprint|null */
|
||||
protected $blueprint;
|
||||
|
||||
/**
|
||||
@@ -127,21 +128,25 @@ class Plugin implements EventSubscriberInterface, ArrayAccess
|
||||
*/
|
||||
protected function isPluginActiveAdmin($plugin_route)
|
||||
{
|
||||
$should_run = false;
|
||||
$active = false;
|
||||
|
||||
/** @var Uri $uri */
|
||||
$uri = $this->grav['uri'];
|
||||
/** @var Config $config */
|
||||
$config = $this->config ?? $this->grav['config'];
|
||||
|
||||
if (strpos($uri->path(), $this->config->get('plugins.admin.route') . '/' . $plugin_route) === false) {
|
||||
$should_run = false;
|
||||
if (strpos($uri->path(), $config->get('plugins.admin.route') . '/' . $plugin_route) === false) {
|
||||
$active = false;
|
||||
} elseif (isset($uri->paths()[1]) && $uri->paths()[1] === $plugin_route) {
|
||||
$should_run = true;
|
||||
$active = true;
|
||||
}
|
||||
|
||||
return $should_run;
|
||||
return $active;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $events
|
||||
* @return void
|
||||
*/
|
||||
protected function enable(array $events)
|
||||
{
|
||||
@@ -164,22 +169,18 @@ class Plugin implements EventSubscriberInterface, ArrayAccess
|
||||
/**
|
||||
* @param array $params
|
||||
* @param string $eventName
|
||||
* @return int
|
||||
*/
|
||||
private function getPriority($params, $eventName)
|
||||
{
|
||||
$grav = Grav::instance();
|
||||
$override = implode('.', ['priorities', $this->name, $eventName, $params[0]]);
|
||||
if ($grav['config']->get($override) !== null) {
|
||||
return $grav['config']->get($override);
|
||||
}
|
||||
if (isset($params[1])) {
|
||||
return $params[1];
|
||||
}
|
||||
return 0;
|
||||
|
||||
return $this->grav['config']->get($override) ?? $params[1] ?? 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $events
|
||||
* @return void
|
||||
*/
|
||||
protected function disable(array $events)
|
||||
{
|
||||
@@ -207,12 +208,13 @@ class Plugin implements EventSubscriberInterface, ArrayAccess
|
||||
*/
|
||||
public function offsetExists($offset)
|
||||
{
|
||||
$this->loadBlueprint();
|
||||
|
||||
if ($offset === 'title') {
|
||||
$offset = 'name';
|
||||
}
|
||||
return isset($this->blueprint[$offset]);
|
||||
|
||||
$blueprint = $this->getBlueprint();
|
||||
|
||||
return isset($blueprint[$offset]);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -223,12 +225,13 @@ class Plugin implements EventSubscriberInterface, ArrayAccess
|
||||
*/
|
||||
public function offsetGet($offset)
|
||||
{
|
||||
$this->loadBlueprint();
|
||||
|
||||
if ($offset === 'title') {
|
||||
$offset = 'name';
|
||||
}
|
||||
return $this->blueprint[$offset] ?? null;
|
||||
|
||||
$blueprint = $this->getBlueprint();
|
||||
|
||||
return $blueprint[$offset] ?? null;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -281,9 +284,12 @@ class Plugin implements EventSubscriberInterface, ArrayAccess
|
||||
*/
|
||||
protected function parseLinks($content, $function, $internal_regex = '(.*)')
|
||||
{
|
||||
$regex = '/\[plugin:(?:' . $this->name . ')\]\(' . $internal_regex . '\)/i';
|
||||
$regex = '/\[plugin:(?:' . preg_quote($this->name, '/') . ')\]\(' . $internal_regex . '\)/i';
|
||||
|
||||
return preg_replace_callback($regex, $function, $content);
|
||||
$result = preg_replace_callback($regex, $function, $content);
|
||||
\assert($result !== null);
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -301,9 +307,12 @@ class Plugin implements EventSubscriberInterface, ArrayAccess
|
||||
*/
|
||||
protected function mergeConfig(PageInterface $page, $deep = false, $params = [], $type = 'plugins')
|
||||
{
|
||||
/** @var Config $config */
|
||||
$config = $this->config ?? $this->grav['config'];
|
||||
|
||||
$class_name = $this->name;
|
||||
$class_name_merged = $class_name . '.merged';
|
||||
$defaults = $this->config->get($type . '.' . $class_name, []);
|
||||
$defaults = $config->get($type . '.' . $class_name, []);
|
||||
$page_header = $page->header();
|
||||
$header = [];
|
||||
|
||||
@@ -356,23 +365,26 @@ class Plugin implements EventSubscriberInterface, ArrayAccess
|
||||
/**
|
||||
* Persists to disk the plugin parameters currently stored in the Grav Config object
|
||||
*
|
||||
* @param string $plugin_name The name of the plugin whose config it should store.
|
||||
*
|
||||
* @param string $name The name of the plugin whose config it should store.
|
||||
* @return bool
|
||||
*/
|
||||
public static function saveConfig($plugin_name)
|
||||
public static function saveConfig($name)
|
||||
{
|
||||
if (!$plugin_name) {
|
||||
if (!$name) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$grav = Grav::instance();
|
||||
|
||||
/** @var UniformResourceLocator $locator */
|
||||
$locator = $grav['locator'];
|
||||
$filename = 'config://plugins/' . $plugin_name . '.yaml';
|
||||
$file = YamlFile::instance($locator->findResource($filename, true, true));
|
||||
$content = $grav['config']->get('plugins.' . $plugin_name);
|
||||
|
||||
$filename = 'config://plugins/' . $name . '.yaml';
|
||||
$file = YamlFile::instance((string)$locator->findResource($filename, true, true));
|
||||
$content = $grav['config']->get('plugins.' . $name);
|
||||
$file->save($content);
|
||||
$file->free();
|
||||
unset($file);
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -384,21 +396,28 @@ class Plugin implements EventSubscriberInterface, ArrayAccess
|
||||
*/
|
||||
public function getBlueprint()
|
||||
{
|
||||
if (!$this->blueprint) {
|
||||
if (null === $this->blueprint) {
|
||||
$this->loadBlueprint();
|
||||
\assert($this->blueprint instanceof Blueprint);
|
||||
}
|
||||
|
||||
return $this->blueprint;
|
||||
}
|
||||
|
||||
/**
|
||||
* Load blueprints.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected function loadBlueprint()
|
||||
{
|
||||
if (!$this->blueprint) {
|
||||
if (null === $this->blueprint) {
|
||||
$grav = Grav::instance();
|
||||
/** @var Plugins $plugins */
|
||||
$plugins = $grav['plugins'];
|
||||
$this->blueprint = $plugins->get($this->name)->blueprints();
|
||||
$data = $plugins->get($this->name);
|
||||
\assert($data !== null);
|
||||
$this->blueprint = $data->blueprints();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,6 +17,7 @@ use Grav\Common\File\CompiledYamlFile;
|
||||
use Grav\Events\PluginsLoadedEvent;
|
||||
use RocketTheme\Toolbox\ResourceLocator\UniformResourceLocator;
|
||||
use RuntimeException;
|
||||
use SplFileInfo;
|
||||
use Symfony\Component\EventDispatcher\EventDispatcher;
|
||||
use function get_class;
|
||||
use function is_object;
|
||||
@@ -27,7 +28,7 @@ use function is_object;
|
||||
*/
|
||||
class Plugins extends Iterator
|
||||
{
|
||||
/** @var array */
|
||||
/** @var array|null */
|
||||
public $formFieldTypes;
|
||||
|
||||
/** @var bool */
|
||||
@@ -46,6 +47,7 @@ class Plugins extends Iterator
|
||||
$iterator = $locator->getIterator('plugins://');
|
||||
|
||||
$plugins = [];
|
||||
/** @var SplFileInfo $directory */
|
||||
foreach ($iterator as $directory) {
|
||||
if (!$directory->isDir()) {
|
||||
continue;
|
||||
@@ -56,7 +58,10 @@ class Plugins extends Iterator
|
||||
sort($plugins, SORT_NATURAL | SORT_FLAG_CASE);
|
||||
|
||||
foreach ($plugins as $plugin) {
|
||||
$this->add($this->loadPlugin($plugin));
|
||||
$object = $this->loadPlugin($plugin);
|
||||
if ($object) {
|
||||
$this->add($object);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -68,13 +73,21 @@ class Plugins extends Iterator
|
||||
$blueprints = [];
|
||||
$formFields = [];
|
||||
|
||||
$grav = Grav::instance();
|
||||
|
||||
/** @var Config $config */
|
||||
$config = $grav['config'];
|
||||
|
||||
/** @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;
|
||||
// Setup only enabled plugins.
|
||||
if ($config["plugins.{$plugin->name}.enabled"] && $plugin instanceof Plugin) {
|
||||
if (isset($plugin->features['blueprints'])) {
|
||||
$blueprints["plugin://{$plugin->name}/blueprints"] = $plugin->features['blueprints'];
|
||||
}
|
||||
if (method_exists($plugin, 'getFormFieldTypes')) {
|
||||
$formFields[get_class($plugin)] = $plugin->features['formfields'] ?? 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -83,7 +96,7 @@ class Plugins extends Iterator
|
||||
arsort($blueprints, SORT_NUMERIC);
|
||||
|
||||
/** @var UniformResourceLocator $locator */
|
||||
$locator = Grav::instance()['locator'];
|
||||
$locator = $grav['locator'];
|
||||
$locator->addPath('blueprints', '', array_keys($blueprints), ['system', 'blueprints']);
|
||||
}
|
||||
|
||||
@@ -150,6 +163,7 @@ class Plugins extends Iterator
|
||||
* Add a plugin
|
||||
*
|
||||
* @param Plugin $plugin
|
||||
* @return void
|
||||
*/
|
||||
public function add($plugin)
|
||||
{
|
||||
@@ -175,8 +189,8 @@ class Plugins extends Iterator
|
||||
*/
|
||||
public static function getPlugins(): array
|
||||
{
|
||||
$grav = Grav::instance();
|
||||
$plugins = $grav['plugins'];
|
||||
/** @var Plugins $plugins */
|
||||
$plugins = Grav::instance()['plugins'];
|
||||
|
||||
$list = [];
|
||||
foreach ($plugins as $instance) {
|
||||
@@ -200,11 +214,13 @@ class Plugins extends Iterator
|
||||
/**
|
||||
* Return list of all plugin data with their blueprints.
|
||||
*
|
||||
* @return array<string,Data>
|
||||
* @return Data[]
|
||||
*/
|
||||
public static function all()
|
||||
{
|
||||
$grav = Grav::instance();
|
||||
|
||||
/** @var Plugins $plugins */
|
||||
$plugins = $grav['plugins'];
|
||||
$list = [];
|
||||
|
||||
|
||||
@@ -105,8 +105,9 @@ class InitializeProcessor extends ProcessorBase
|
||||
$this->initializeUri($config);
|
||||
|
||||
// Grav may return redirect response right away.
|
||||
if ($config->get('system.pages.redirect_trailing_slash', false)) {
|
||||
$response = $this->handleRedirectRequest($request);
|
||||
$redirectCode = (int)$config->get('system.pages.redirect_trailing_slash', 1);
|
||||
if ($redirectCode) {
|
||||
$response = $this->handleRedirectRequest($request, $redirectCode > 300 ? $redirectCode : null);
|
||||
if ($response) {
|
||||
$this->stopTimer('_init');
|
||||
|
||||
@@ -413,7 +414,7 @@ class InitializeProcessor extends ProcessorBase
|
||||
$this->stopTimer('_init_uri');
|
||||
}
|
||||
|
||||
protected function handleRedirectRequest(RequestInterface $request): ?ResponseInterface
|
||||
protected function handleRedirectRequest(RequestInterface $request, int $code = null): ?ResponseInterface
|
||||
{
|
||||
if (!in_array($request->getMethod(), ['GET', 'HEAD'])) {
|
||||
return null;
|
||||
@@ -426,7 +427,7 @@ class InitializeProcessor extends ProcessorBase
|
||||
|
||||
if ($path !== $root && $path !== $root . '/' && Utils::endsWith($path, '/')) {
|
||||
// Use permanent redirect for SEO reasons.
|
||||
return $this->container->getRedirectResponse((string)$uri->withPath(rtrim($path, '/')), 301);
|
||||
return $this->container->getRedirectResponse((string)$uri->withPath(rtrim($path, '/')), $code);
|
||||
}
|
||||
|
||||
return null;
|
||||
|
||||
@@ -77,32 +77,46 @@ class PagesServiceProvider implements ServiceProviderInterface
|
||||
}
|
||||
}
|
||||
|
||||
$url = $pages->route($page->route());
|
||||
$route = $page->route();
|
||||
if ($route && \in_array($uri->method(), ['GET', 'HEAD'], true)) {
|
||||
$pageExtension = $page->urlExtension();
|
||||
$url = $pages->route($route) . $pageExtension;
|
||||
|
||||
if ($uri->params()) {
|
||||
if ($url === '/') { //Avoid double slash
|
||||
$url = $uri->params();
|
||||
} else {
|
||||
$url .= $uri->params();
|
||||
if ($uri->params()) {
|
||||
if ($url === '/') { //Avoid double slash
|
||||
$url = $uri->params();
|
||||
} else {
|
||||
$url .= $uri->params();
|
||||
}
|
||||
}
|
||||
if ($uri->query()) {
|
||||
$url .= '?' . $uri->query();
|
||||
}
|
||||
if ($uri->fragment()) {
|
||||
$url .= '#' . $uri->fragment();
|
||||
}
|
||||
}
|
||||
if ($uri->query()) {
|
||||
$url .= '?' . $uri->query();
|
||||
}
|
||||
if ($uri->fragment()) {
|
||||
$url .= '#' . $uri->fragment();
|
||||
}
|
||||
|
||||
/** @var Language $language */
|
||||
$language = $grav['language'];
|
||||
/** @var Language $language */
|
||||
$language = $grav['language'];
|
||||
|
||||
// Language-specific redirection scenarios
|
||||
if ($language->enabled() && ($language->isLanguageInUrl() xor $language->isIncludeDefaultLanguage())) {
|
||||
$grav->redirect($url);
|
||||
}
|
||||
// Default route test and redirect
|
||||
if ($config->get('system.pages.redirect_default_route') && $page->route() !== $path) {
|
||||
$grav->redirect($url);
|
||||
$redirectCode = (int)$config->get('system.pages.redirect_default_route', 0);
|
||||
|
||||
// Language-specific redirection scenarios
|
||||
if ($language->enabled() && ($language->isLanguageInUrl() xor $language->isIncludeDefaultLanguage())) {
|
||||
$grav->redirect($url, $redirectCode);
|
||||
}
|
||||
|
||||
// Default route test and redirect
|
||||
if ($redirectCode) {
|
||||
$uriExtension = $uri->extension();
|
||||
$uriExtension = null !== $uriExtension ? '.' . $uriExtension : '';
|
||||
|
||||
if ($route !== $path || ($pageExtension !== $uriExtension
|
||||
&& \in_array($pageExtension, ['', '.htm', '.html'], true)
|
||||
&& \in_array($uriExtension, ['', '.htm', '.html'], true))) {
|
||||
$grav->redirect($url, $redirectCode);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -9,9 +9,9 @@
|
||||
|
||||
namespace Grav\Common;
|
||||
|
||||
use Grav\Common\Page\Interfaces\PageInterface;
|
||||
use Grav\Common\Config\Config;
|
||||
use RocketTheme\Toolbox\File\YamlFile;
|
||||
use RocketTheme\Toolbox\ResourceLocator\UniformResourceLocator;
|
||||
|
||||
/**
|
||||
* Class Theme
|
||||
@@ -44,53 +44,30 @@ class Theme extends Plugin
|
||||
/**
|
||||
* Persists to disk the theme parameters currently stored in the Grav Config object
|
||||
*
|
||||
* @param string $theme_name The name of the theme whose config it should store.
|
||||
* @param string $name The name of the theme whose config it should store.
|
||||
* @return bool
|
||||
*/
|
||||
public static function saveConfig($theme_name)
|
||||
public static function saveConfig($name)
|
||||
{
|
||||
if (!$theme_name) {
|
||||
if (!$name) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$grav = Grav::instance();
|
||||
|
||||
/** @var UniformResourceLocator $locator */
|
||||
$locator = $grav['locator'];
|
||||
$filename = 'config://themes/' . $theme_name . '.yaml';
|
||||
$file = YamlFile::instance($locator->findResource($filename, true, true));
|
||||
$content = $grav['config']->get('themes.' . $theme_name);
|
||||
|
||||
$filename = 'config://themes/' . $name . '.yaml';
|
||||
$file = YamlFile::instance((string)$locator->findResource($filename, true, true));
|
||||
$content = $grav['config']->get('themes.' . $name);
|
||||
$file->save($content);
|
||||
$file->free();
|
||||
unset($file);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Override the mergeConfig method to work for themes
|
||||
*
|
||||
* @param PageInterface $page
|
||||
* @param string $deep
|
||||
* @param array $params
|
||||
* @param string $type
|
||||
* @return Data\Data
|
||||
*/
|
||||
protected function mergeConfig(PageInterface $page, $deep = 'merge', $params = [], $type = 'themes')
|
||||
{
|
||||
return parent::mergeConfig($page, $deep, $params, $type);
|
||||
}
|
||||
|
||||
/**
|
||||
* Simpler getter for the theme blueprint
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public function getBlueprint()
|
||||
{
|
||||
if (!$this->blueprint) {
|
||||
$this->loadBlueprint();
|
||||
}
|
||||
return $this->blueprint;
|
||||
}
|
||||
|
||||
/**
|
||||
* Load blueprints.
|
||||
*
|
||||
@@ -100,8 +77,11 @@ class Theme extends Plugin
|
||||
{
|
||||
if (!$this->blueprint) {
|
||||
$grav = Grav::instance();
|
||||
/** @var Themes $themes */
|
||||
$themes = $grav['themes'];
|
||||
$this->blueprint = $themes->get($this->name)->blueprints();
|
||||
$data = $themes->get($this->name);
|
||||
\assert($data !== null);
|
||||
$this->blueprint = $data->blueprints();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -33,10 +33,8 @@ class Themes extends Iterator
|
||||
{
|
||||
/** @var Grav */
|
||||
protected $grav;
|
||||
|
||||
/** @var Config */
|
||||
protected $config;
|
||||
|
||||
/** @var bool */
|
||||
protected $inited = false;
|
||||
|
||||
@@ -95,6 +93,20 @@ class Themes extends Iterator
|
||||
$events->addSubscriber($instance);
|
||||
}
|
||||
|
||||
// Register blueprints.
|
||||
if (is_dir('theme://blueprints/pages')) {
|
||||
/** @var UniformResourceLocator $locator */
|
||||
$locator = $this->grav['locator'];
|
||||
$locator->addPath('blueprints', '', ['theme://blueprints'], ['user', 'blueprints']);
|
||||
}
|
||||
|
||||
// Register form fields.
|
||||
if (method_exists($instance, 'getFormFieldTypes')) {
|
||||
/** @var Plugins $plugins */
|
||||
$plugins = $this->grav['plugins'];
|
||||
$plugins->formFieldTypes = $instance->getFormFieldTypes() + $plugins->formFieldTypes;
|
||||
}
|
||||
|
||||
$this->grav['theme'] = $instance;
|
||||
|
||||
$this->grav->fireEvent('onThemeInitialized');
|
||||
@@ -382,7 +394,10 @@ class Themes extends Iterator
|
||||
}
|
||||
|
||||
// Try Old style theme classes
|
||||
$path = strtolower(preg_replace('#\\\|_(?!.+\\\)#', '/', $class));
|
||||
$path = preg_replace('#\\\|_(?!.+\\\)#', '/', $class);
|
||||
\assert(null !== $path);
|
||||
|
||||
$path = strtolower($path);
|
||||
$file = $locator("themes://{$path}/theme.php") ?: $locator("themes://{$path}/{$path}.php");
|
||||
|
||||
// Load class
|
||||
|
||||
@@ -21,6 +21,7 @@ use RocketTheme\Toolbox\Event\Event;
|
||||
use RuntimeException;
|
||||
use function array_key_exists;
|
||||
use function count;
|
||||
use function in_array;
|
||||
use function is_array;
|
||||
use function is_string;
|
||||
use function strlen;
|
||||
@@ -394,7 +395,7 @@ class Uri
|
||||
* Return the Extension of the URI
|
||||
*
|
||||
* @param string|null $default
|
||||
* @return string The extension of the URI
|
||||
* @return string|null The extension of the URI
|
||||
*/
|
||||
public function extension($default = null)
|
||||
{
|
||||
@@ -1408,18 +1409,14 @@ class Uri
|
||||
/**
|
||||
* Check if this is a valid Grav extension
|
||||
*
|
||||
* @param string $extension
|
||||
* @param string|null $extension
|
||||
* @return bool
|
||||
*/
|
||||
public function isValidExtension($extension)
|
||||
public function isValidExtension($extension): bool
|
||||
{
|
||||
$valid_page_types = implode('|', Utils::getSupportPageTypes());
|
||||
$extension = (string)$extension;
|
||||
|
||||
// Strip the file extension for valid page types
|
||||
if (preg_match('/(' . $valid_page_types . ')/', $extension)) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
return $extension !== '' && in_array($extension, Utils::getSupportPageTypes(), true);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -154,8 +154,6 @@ class CleanCommand extends Command
|
||||
'vendor/itsgoingd/clockwork/.gitattributes',
|
||||
'vendor/itsgoingd/clockwork/CHANGELOG.md',
|
||||
'vendor/itsgoingd/clockwork/composer.json',
|
||||
'vendor/kodus/psr7-server/composer.json',
|
||||
'vendor/kodus/psr7-server/CHANGELOG.md',
|
||||
'vendor/league/climate/composer.json',
|
||||
'vendor/league/climate/CHANGELOG.md',
|
||||
'vendor/league/climate/CONTRIBUTING.md',
|
||||
@@ -197,6 +195,9 @@ class CleanCommand extends Command
|
||||
'vendor/nyholm/psr7/phpstan.neon.dist',
|
||||
'vendor/nyholm/psr7/CHANGELOG.md',
|
||||
'vendor/nyholm/psr7/psalm.xml',
|
||||
'vendor/nyholm/psr7-server/.github',
|
||||
'vendor/nyholm/psr7-server/composer.json',
|
||||
'vendor/nyholm/psr7-server/CHANGELOG.md',
|
||||
'vendor/phive/twig-extensions-deferred/.gitignore',
|
||||
'vendor/phive/twig-extensions-deferred/.travis.yml',
|
||||
'vendor/phive/twig-extensions-deferred/composer.json',
|
||||
|
||||
@@ -14,11 +14,13 @@ namespace Grav\Framework\Controller\Traits;
|
||||
use Grav\Common\Config\Config;
|
||||
use Grav\Common\Debugger;
|
||||
use Grav\Common\Grav;
|
||||
use Grav\Common\Utils;
|
||||
use Grav\Framework\Psr7\Response;
|
||||
use Grav\Framework\RequestHandler\Exception\RequestException;
|
||||
use Grav\Framework\Route\Route;
|
||||
use Psr\Http\Message\ResponseInterface;
|
||||
use Psr\Http\Message\ServerRequestInterface;
|
||||
use Psr\Http\Message\StreamInterface;
|
||||
use Throwable;
|
||||
use function get_class;
|
||||
use function in_array;
|
||||
@@ -76,6 +78,55 @@ trait ControllerResponseTrait
|
||||
return new Response($code, $headers, json_encode($content));
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $filename
|
||||
* @param string|resource|StreamInterface $resource
|
||||
* @param array|null $headers
|
||||
* @param array|null $options
|
||||
* @return ResponseInterface
|
||||
*/
|
||||
protected function createDownloadResponse(string $filename, $resource, array $headers = null, array $options = null): ResponseInterface
|
||||
{
|
||||
// Required for IE, otherwise Content-Disposition may be ignored
|
||||
if (ini_get('zlib.output_compression')) {
|
||||
@ini_set('zlib.output_compression', 'Off');
|
||||
}
|
||||
|
||||
$headers = $headers ?? [];
|
||||
$options = $options ?? ['force_download' => true];
|
||||
|
||||
$file_parts = pathinfo($filename);
|
||||
|
||||
if (!isset($headers['Content-Type'])) {
|
||||
$mimetype = Utils::getMimeByExtension($file_parts['extension']);
|
||||
|
||||
$headers['Content-Type'] = $mimetype;
|
||||
}
|
||||
|
||||
// TODO: add multipart download support.
|
||||
//$headers['Accept-Ranges'] = 'bytes';
|
||||
|
||||
if (!empty($options['force_download'])) {
|
||||
$headers['Content-Disposition'] = 'attachment; filename="' . $file_parts['basename'] . '"';
|
||||
}
|
||||
|
||||
if (!isset($headers['Content-Length'])) {
|
||||
$realpath = realpath($filename);
|
||||
if ($realpath) {
|
||||
$headers['Content-Length'] = filesize($realpath);
|
||||
}
|
||||
}
|
||||
|
||||
$headers += [
|
||||
'Expires' => 'Mon, 26 Jul 1997 05:00:00 GMT',
|
||||
'Last-Modified' => gmdate('D, d M Y H:i:s') . ' GMT',
|
||||
'Cache-Control' => 'no-store, no-cache, must-revalidate',
|
||||
'Pragma' => 'no-cache'
|
||||
];
|
||||
|
||||
return new Response(200, $headers, $resource);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $url
|
||||
* @param int|null $code
|
||||
|
||||
@@ -380,7 +380,7 @@ class FlexIndex extends ObjectIndex implements FlexCollectionInterface, FlexInde
|
||||
|
||||
// Handle primary key alias.
|
||||
$keyField = $this->getFlexDirectory()->getStorage()->getKeyField();
|
||||
if (isset($orderings[$keyField])) {
|
||||
if ($keyField !== 'key' && $keyField !== 'storage_key' && isset($orderings[$keyField])) {
|
||||
$orderings['key'] = $orderings[$keyField];
|
||||
unset($orderings[$keyField]);
|
||||
}
|
||||
|
||||
@@ -885,6 +885,14 @@ class FlexObject implements FlexObjectInterface, FlexAuthorizeInterface
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Clone object.
|
||||
*/
|
||||
public function __clone()
|
||||
{
|
||||
// Allows future compatibility as parent::__clone() works.
|
||||
}
|
||||
|
||||
protected function markAsCopy(): void
|
||||
{
|
||||
$meta = $this->getMetaData();
|
||||
|
||||
@@ -16,7 +16,6 @@ use Grav\Common\Grav;
|
||||
use Grav\Common\Page\Interfaces\PageInterface;
|
||||
use Grav\Common\Page\Traits\PageFormTrait;
|
||||
use Grav\Common\User\Interfaces\UserCollectionInterface;
|
||||
use Grav\Framework\File\Formatter\YamlFormatter;
|
||||
use Grav\Framework\Flex\FlexObject;
|
||||
use Grav\Framework\Flex\Interfaces\FlexObjectInterface;
|
||||
use Grav\Framework\Flex\Interfaces\FlexTranslateInterface;
|
||||
@@ -50,6 +49,20 @@ class FlexPageObject extends FlexObject implements PageInterface, FlexTranslateI
|
||||
|
||||
/** @var array|null */
|
||||
protected $_reorder;
|
||||
/** @var FlexPageObject|null */
|
||||
protected $_original;
|
||||
|
||||
/**
|
||||
* Clone page.
|
||||
*/
|
||||
public function __clone()
|
||||
{
|
||||
parent::__clone();
|
||||
|
||||
if (isset($this->header)) {
|
||||
$this->header = clone($this->header);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
@@ -242,6 +255,32 @@ class FlexPageObject extends FlexObject implements PageInterface, FlexTranslateI
|
||||
return parent::save();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the Page Unmodified (original) version of the page.
|
||||
*
|
||||
* Assumes that object has been cloned before modifying it.
|
||||
*
|
||||
* @return FlexPageObject|null The original version of the page.
|
||||
*/
|
||||
public function getOriginal()
|
||||
{
|
||||
return $this->_original;
|
||||
}
|
||||
|
||||
/**
|
||||
* Store the Page Unmodified (original) version of the page.
|
||||
*
|
||||
* Can be called multiple times, only the first call matters.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function storeOriginal(): void
|
||||
{
|
||||
if (null === $this->_original) {
|
||||
$this->_original = clone $this;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get display order for the associated media.
|
||||
*
|
||||
@@ -398,23 +437,6 @@ class FlexPageObject extends FlexObject implements PageInterface, FlexTranslateI
|
||||
unset($elements['content']);
|
||||
}
|
||||
|
||||
// TODO: Remove: RAW frontmatter support has been moved to Flex-Objects v1.0.2 controller.
|
||||
if (isset($elements['frontmatter'])) {
|
||||
$formatter = new YamlFormatter();
|
||||
try {
|
||||
// Replace the whole header except for media order, which is used in admin.
|
||||
$media_order = $elements['media_order'] ?? null;
|
||||
$elements['header'] = $formatter->decode($elements['frontmatter']);
|
||||
if ($media_order) {
|
||||
$elements['header']['media_order'] = $media_order;
|
||||
}
|
||||
} catch (RuntimeException $e) {
|
||||
throw new RuntimeException('Badly formatted markdown');
|
||||
}
|
||||
|
||||
unset($elements['frontmatter']);
|
||||
}
|
||||
|
||||
if (!$extended) {
|
||||
$folder = !empty($elements['folder']) ? trim($elements['folder']) : '';
|
||||
|
||||
|
||||
@@ -27,6 +27,8 @@ trait PageAuthorsTrait
|
||||
{
|
||||
/** @var array<int,UserInterface> */
|
||||
private $_authors;
|
||||
/** @var array|null */
|
||||
private $_permissionsCache;
|
||||
|
||||
/**
|
||||
* Returns true if object has the named author.
|
||||
@@ -70,15 +72,19 @@ trait PageAuthorsTrait
|
||||
*/
|
||||
public function getPermissions(bool $inherit = false)
|
||||
{
|
||||
$permissions = [];
|
||||
if ($inherit && $this->getNestedProperty('header.permissions.inherit', true)) {
|
||||
$parent = $this->parent();
|
||||
if ($parent && method_exists($parent, 'getPermissions')) {
|
||||
$permissions = $parent->getPermissions($inherit);
|
||||
if (null === $this->_permissionsCache) {
|
||||
$permissions = [];
|
||||
if ($inherit && $this->getNestedProperty('header.permissions.inherit', true)) {
|
||||
$parent = $this->parent();
|
||||
if ($parent && method_exists($parent, 'getPermissions')) {
|
||||
$permissions = $parent->getPermissions($inherit);
|
||||
}
|
||||
}
|
||||
|
||||
$this->_permissionsCache = $this->loadPermissions($permissions);
|
||||
}
|
||||
|
||||
return $this->loadPermissions($permissions);
|
||||
return $this->_permissionsCache;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -277,6 +277,8 @@ trait PageLegacyTrait
|
||||
throw new RuntimeException('Failed: Cannot set page parent to a child of current page');
|
||||
}
|
||||
|
||||
$this->storeOriginal();
|
||||
|
||||
// TODO:
|
||||
throw new RuntimeException(__METHOD__ . '(): Not Implemented');
|
||||
}
|
||||
@@ -292,6 +294,8 @@ trait PageLegacyTrait
|
||||
*/
|
||||
public function copy(PageInterface $parent = null)
|
||||
{
|
||||
$this->storeOriginal();
|
||||
|
||||
$filesystem = Filesystem::getInstance(false);
|
||||
|
||||
$parentStorageKey = ltrim($filesystem->dirname("/{$this->getMasterKey()}"), '/');
|
||||
@@ -715,8 +719,9 @@ trait PageLegacyTrait
|
||||
|
||||
/** @var UniformResourceLocator $locator */
|
||||
$locator = Grav::instance()['locator'];
|
||||
$folder = $locator->isStream($folder) ? $locator->getResource($folder) : GRAV_ROOT . "/{$folder}";
|
||||
|
||||
return $locator->findResource($folder, true, true) . '/' . ($this->isPage() ? $this->name() : 'default.md');
|
||||
return $folder . '/' . ($this->isPage() ? $this->name() : 'default.md');
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -733,8 +738,9 @@ trait PageLegacyTrait
|
||||
|
||||
/** @var UniformResourceLocator $locator */
|
||||
$locator = Grav::instance()['locator'];
|
||||
$folder = $locator->isStream($folder) ? $locator->getResource($folder, false) : $folder;
|
||||
|
||||
return $locator->findResource($folder, false, true) . '/' . ($this->isPage() ? $this->name() : 'default.md');
|
||||
return $folder . '/' . ($this->isPage() ? $this->name() : 'default.md');
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1085,18 +1091,6 @@ trait PageLegacyTrait
|
||||
return $this->exists() || is_dir($this->getStorageFolder() ?? '');
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the Page Unmodified (original) version of the page.
|
||||
*
|
||||
* Assumes that object has been cloned before modifying it.
|
||||
*
|
||||
* @return PageInterface|null The original version of the page.
|
||||
*/
|
||||
public function getOriginal()
|
||||
{
|
||||
return $this->getFlexDirectory()->getObject($this->getKey());
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the action.
|
||||
*
|
||||
|
||||
@@ -18,6 +18,7 @@ use Grav\Common\Uri;
|
||||
use Grav\Framework\Filesystem\Filesystem;
|
||||
use RocketTheme\Toolbox\ResourceLocator\UniformResourceLocator;
|
||||
use RuntimeException;
|
||||
use function dirname;
|
||||
use function is_string;
|
||||
|
||||
/**
|
||||
@@ -32,6 +33,8 @@ trait PageRoutableTrait
|
||||
private $_route;
|
||||
/** @var string|null */
|
||||
private $_path;
|
||||
/** @var PageInterface|null */
|
||||
private $_parentCache;
|
||||
|
||||
/**
|
||||
* Returns the page extension, got from the page `url_extension` config and falls back to the
|
||||
@@ -317,7 +320,7 @@ trait PageRoutableTrait
|
||||
|
||||
/** @var UniformResourceLocator $locator */
|
||||
$locator = Grav::instance()['locator'];
|
||||
$path = $locator->findResource($folder, false);
|
||||
$path = $locator->isStream($folder) ? $locator->findResource($folder, false) : $folder;
|
||||
|
||||
return is_string($path) ? $path : null;
|
||||
}
|
||||
@@ -350,7 +353,7 @@ trait PageRoutableTrait
|
||||
if ($folder) {
|
||||
/** @var UniformResourceLocator $locator */
|
||||
$locator = Grav::instance()['locator'];
|
||||
$folder = $locator($folder);
|
||||
$folder = $locator->isStream($folder) ? $locator->getResource($folder) : GRAV_ROOT . "/{$folder}";
|
||||
}
|
||||
|
||||
return $this->_path = is_string($folder) ? $folder : null;
|
||||
@@ -413,13 +416,12 @@ trait PageRoutableTrait
|
||||
throw new RuntimeException(__METHOD__ . '(PageInterface): Not Implemented');
|
||||
}
|
||||
|
||||
if ($this->root()) {
|
||||
return null;
|
||||
if ($this->_parentCache || $this->root()) {
|
||||
return $this->_parentCache;
|
||||
}
|
||||
|
||||
$filesystem = Filesystem::getInstance(false);
|
||||
$directory = $this->getFlexDirectory();
|
||||
$parentKey = ltrim($filesystem->dirname("/{$this->getKey()}"), '/');
|
||||
$parentKey = ltrim(dirname("/{$this->getKey()}"), '/');
|
||||
if ($parentKey) {
|
||||
$parent = $directory->getObject($parentKey);
|
||||
$language = $this->getLanguage();
|
||||
@@ -427,12 +429,14 @@ trait PageRoutableTrait
|
||||
$parent = $parent->getTranslation($language) ?? $parent;
|
||||
}
|
||||
|
||||
return $parent;
|
||||
$this->_parentCache = $parent;
|
||||
} else {
|
||||
$index = $directory->getIndex();
|
||||
|
||||
$this->_parentCache = method_exists($index, 'getRoot') ? $index->getRoot() : null;
|
||||
}
|
||||
|
||||
$index = $directory->getIndex();
|
||||
|
||||
return method_exists($index, 'getRoot') ? $index->getRoot() : null;
|
||||
return $this->_parentCache;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -186,10 +186,10 @@ abstract class AbstractFilesystemStorage implements FlexStorageInterface
|
||||
$locator = Grav::instance()['locator'];
|
||||
|
||||
if (!$locator->isStream($path)) {
|
||||
return $path;
|
||||
return GRAV_ROOT . "/{$path}";
|
||||
}
|
||||
|
||||
return (string)($locator->findResource($path) ?: $locator->findResource($path, true, true));
|
||||
return $locator->getResource($path);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -83,6 +83,8 @@ class FileStorage extends FolderStorage
|
||||
$path = $this->getPathFromKey($src);
|
||||
$file = $this->getFile($path);
|
||||
$file->delete();
|
||||
$file->free();
|
||||
unset($file);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -377,12 +377,14 @@ class FolderStorage extends AbstractFilesystemStorage
|
||||
$file = $this->getFile($path);
|
||||
try {
|
||||
$data = (array)$file->content();
|
||||
$file->free();
|
||||
if (isset($data[0])) {
|
||||
throw new RuntimeException('Broken object file');
|
||||
}
|
||||
} catch (RuntimeException $e) {
|
||||
$data = ['__ERROR' => $e->getMessage()];
|
||||
} finally {
|
||||
$file->free();
|
||||
unset($file);
|
||||
}
|
||||
|
||||
$data['__META'] = $this->getObjectMeta($key);
|
||||
@@ -426,13 +428,17 @@ class FolderStorage extends AbstractFilesystemStorage
|
||||
|
||||
$file->save($row);
|
||||
|
||||
/** @var UniformResourceLocator $locator */
|
||||
$locator = Grav::instance()['locator'];
|
||||
if ($locator->isStream($path)) {
|
||||
$locator->clearCache();
|
||||
}
|
||||
} catch (RuntimeException $e) {
|
||||
throw new RuntimeException(sprintf('Flex saveFile(%s): %s', $path ?? $key, $e->getMessage()));
|
||||
} finally {
|
||||
/** @var UniformResourceLocator $locator */
|
||||
$locator = Grav::instance()['locator'];
|
||||
$locator->clearCache();
|
||||
|
||||
if (isset($file)) {
|
||||
$file->free();
|
||||
unset($file);
|
||||
}
|
||||
}
|
||||
|
||||
$row['__META'] = $this->getObjectMeta($key, true);
|
||||
@@ -452,14 +458,14 @@ class FolderStorage extends AbstractFilesystemStorage
|
||||
if ($file->exists()) {
|
||||
$file->delete();
|
||||
}
|
||||
|
||||
/** @var UniformResourceLocator $locator */
|
||||
$locator = Grav::instance()['locator'];
|
||||
if ($locator->isStream($filename)) {
|
||||
$locator->clearCache($filename);
|
||||
}
|
||||
} catch (RuntimeException $e) {
|
||||
throw new RuntimeException(sprintf('Flex deleteFile(%s): %s', $filename, $e->getMessage()));
|
||||
} finally {
|
||||
/** @var UniformResourceLocator $locator */
|
||||
$locator = Grav::instance()['locator'];
|
||||
$locator->clearCache();
|
||||
|
||||
$file->free();
|
||||
}
|
||||
|
||||
return $data;
|
||||
@@ -474,14 +480,12 @@ class FolderStorage extends AbstractFilesystemStorage
|
||||
{
|
||||
try {
|
||||
Folder::copy($this->resolvePath($src), $this->resolvePath($dst));
|
||||
|
||||
/** @var UniformResourceLocator $locator */
|
||||
$locator = Grav::instance()['locator'];
|
||||
if ($locator->isStream($src) || $locator->isStream($dst)) {
|
||||
$locator->clearCache();
|
||||
}
|
||||
} catch (RuntimeException $e) {
|
||||
throw new RuntimeException(sprintf('Flex copyFolder(%s, %s): %s', $src, $dst, $e->getMessage()));
|
||||
} finally {
|
||||
/** @var UniformResourceLocator $locator */
|
||||
$locator = Grav::instance()['locator'];
|
||||
$locator->clearCache();
|
||||
}
|
||||
|
||||
return true;
|
||||
@@ -496,14 +500,12 @@ class FolderStorage extends AbstractFilesystemStorage
|
||||
{
|
||||
try {
|
||||
Folder::move($this->resolvePath($src), $this->resolvePath($dst));
|
||||
|
||||
/** @var UniformResourceLocator $locator */
|
||||
$locator = Grav::instance()['locator'];
|
||||
if ($locator->isStream($src) || $locator->isStream($dst)) {
|
||||
$locator->clearCache();
|
||||
}
|
||||
} catch (RuntimeException $e) {
|
||||
throw new RuntimeException(sprintf('Flex moveFolder(%s, %s): %s', $src, $dst, $e->getMessage()));
|
||||
} finally {
|
||||
/** @var UniformResourceLocator $locator */
|
||||
$locator = Grav::instance()['locator'];
|
||||
$locator->clearCache();
|
||||
}
|
||||
|
||||
return true;
|
||||
@@ -517,17 +519,13 @@ class FolderStorage extends AbstractFilesystemStorage
|
||||
protected function deleteFolder(string $path, bool $include_target = false): bool
|
||||
{
|
||||
try {
|
||||
$success = Folder::delete($this->resolvePath($path), $include_target);
|
||||
|
||||
/** @var UniformResourceLocator $locator */
|
||||
$locator = Grav::instance()['locator'];
|
||||
if ($locator->isStream($path)) {
|
||||
$locator->clearCache();
|
||||
}
|
||||
|
||||
return $success;
|
||||
return Folder::delete($this->resolvePath($path), $include_target);
|
||||
} catch (RuntimeException $e) {
|
||||
throw new RuntimeException(sprintf('Flex deleteFolder(%s): %s', $path, $e->getMessage()));
|
||||
} finally {
|
||||
/** @var UniformResourceLocator $locator */
|
||||
$locator = Grav::instance()['locator'];
|
||||
$locator->clearCache();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -669,7 +667,14 @@ class FolderStorage extends AbstractFilesystemStorage
|
||||
/** @var string $pattern */
|
||||
$pattern = !empty($options['pattern']) ? $options['pattern'] : $this->dataPattern;
|
||||
|
||||
$this->dataFolder = $options['folder'];
|
||||
/** @var UniformResourceLocator $locator */
|
||||
$locator = Grav::instance()['locator'];
|
||||
$folder = $options['folder'];
|
||||
if ($locator->isStream($folder)) {
|
||||
$folder = $locator->getResource($folder, false);
|
||||
}
|
||||
|
||||
$this->dataFolder = $folder;
|
||||
$this->dataFile = $options['file'] ?? 'item';
|
||||
$this->dataExt = $extension;
|
||||
if (mb_strpos($pattern, '{FILE}') === false && mb_strpos($pattern, '{EXT}') === false) {
|
||||
|
||||
@@ -414,9 +414,13 @@ class SimpleStorage extends AbstractFilesystemStorage
|
||||
}
|
||||
$file->save($content);
|
||||
$this->modified = (int)$file->modified(); // cast false to 0
|
||||
$file->free();
|
||||
} catch (RuntimeException $e) {
|
||||
throw new RuntimeException(sprintf('Flex save(): %s', $e->getMessage()));
|
||||
} finally {
|
||||
if (isset($file)) {
|
||||
$file->free();
|
||||
unset($file);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -453,6 +457,10 @@ class SimpleStorage extends AbstractFilesystemStorage
|
||||
$data = new Data($content);
|
||||
$content = $data->get($this->prefix);
|
||||
}
|
||||
|
||||
$file->free();
|
||||
unset($file);
|
||||
|
||||
$this->data = $content;
|
||||
|
||||
$list = [];
|
||||
|
||||
Reference in New Issue
Block a user