mirror of
https://github.com/getgrav/grav.git
synced 2025-10-26 00:46:07 +02:00
@@ -5,10 +5,12 @@
|
||||
* Added `Flex Pages` to Grav core and removed Flex Objects plugin dependency
|
||||
* Added `Utils::simpleTemplate()` method for very simple variable templating
|
||||
* Added `array_diff()` twig function
|
||||
* Added `template_from_string()` twig function
|
||||
1. [](#improved)
|
||||
* Improved `Flex Users`: obey blueprints and allow Flex to be used in admin only
|
||||
* Improved `Flex` to support custom site template paths
|
||||
* Changed Twig `{% cache %}` tag to not need unique key, and `lifetime` is now optional
|
||||
* Added mime support for file formatters
|
||||
1. [](#bugfix)
|
||||
* Fixed `Page::untranslatedLanguages()` not being symmetrical to `Page::translatedLanguages()`
|
||||
* Fixed `Flex Pages` not calling `onPageProcessed` event when cached
|
||||
|
||||
@@ -34,6 +34,7 @@ config:
|
||||
dir: asc
|
||||
|
||||
site:
|
||||
hidden: true
|
||||
templates:
|
||||
collection:
|
||||
paths:
|
||||
|
||||
@@ -91,7 +91,12 @@ config:
|
||||
icon: check
|
||||
label: PLUGIN_ADMIN.SAVE
|
||||
|
||||
# Preview View
|
||||
preview:
|
||||
enabled: true
|
||||
|
||||
site:
|
||||
hidden: true
|
||||
templates:
|
||||
collection:
|
||||
paths:
|
||||
|
||||
@@ -17,7 +17,6 @@ use Grav\Common\Page\Flex\Traits\PageContentTrait;
|
||||
use Grav\Common\Page\Flex\Traits\PageLegacyTrait;
|
||||
use Grav\Common\Page\Flex\Traits\PageRoutableTrait;
|
||||
use Grav\Common\Page\Flex\Traits\PageTranslateTrait;
|
||||
use Grav\Common\Page\Interfaces\PageInterface;
|
||||
use Grav\Common\Page\Pages;
|
||||
use Grav\Common\Utils;
|
||||
use Grav\Framework\Flex\FlexObject;
|
||||
@@ -144,6 +143,10 @@ class PageObject extends FlexPageObject
|
||||
return $instance;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $ordering
|
||||
* @return PageCollection
|
||||
*/
|
||||
protected function reorderSiblings(array $ordering)
|
||||
{
|
||||
$storageKey = $this->getStorageKey();
|
||||
@@ -165,7 +168,8 @@ class PageObject extends FlexPageObject
|
||||
$parent = $this->parent();
|
||||
|
||||
/** @var PageCollection $siblings */
|
||||
$siblings = $parent ? $parent->children()->withVisible()->getCollection() : [];
|
||||
$siblings = $parent ? $parent->children() : null;
|
||||
$siblings = $siblings ? $siblings->withVisible()->getCollection() : null;
|
||||
if ($siblings) {
|
||||
$ordering = array_flip($ordering);
|
||||
if ($storageKey !== null) {
|
||||
@@ -182,6 +186,8 @@ class PageObject extends FlexPageObject
|
||||
}
|
||||
$siblings = $siblings->orderBy(['order' => 'ASC']);
|
||||
$siblings->removeElement($this);
|
||||
} else {
|
||||
$siblings = $this->getFlexDirectory()->createCollection([]);
|
||||
}
|
||||
|
||||
return $siblings;
|
||||
@@ -496,7 +502,13 @@ class PageObject extends FlexPageObject
|
||||
|
||||
// If parent changes and page is visible, move it to be the last item.
|
||||
if ($parent && !empty($elements['order']) && $parent !== $this->parent()) {
|
||||
$elements['order'] = ((int)$parent->children()->visible()->sort(['order' => 'ASC'])->last()->order()) + 1;
|
||||
$siblings = $parent->children();
|
||||
$siblings = $siblings ? $siblings->visible()->sort(['order' => 'ASC']) : null;
|
||||
if ($siblings && $siblings->count()) {
|
||||
$elements['order'] = ((int)$siblings->last()->order()) + 1;
|
||||
} else {
|
||||
$elements['order'] = 1;
|
||||
}
|
||||
}
|
||||
|
||||
$parentKey = $parent->getStorageKey();
|
||||
|
||||
@@ -14,6 +14,8 @@ namespace Grav\Common\Page\Flex;
|
||||
use Grav\Common\Debugger;
|
||||
use Grav\Common\Grav;
|
||||
use Grav\Common\Language\Language;
|
||||
use Grav\Framework\File\MarkdownFile;
|
||||
use Grav\Framework\File\YamlFile;
|
||||
use Grav\Framework\Flex\Storage\FolderStorage;
|
||||
use RocketTheme\Toolbox\ResourceLocator\UniformResourceLocator;
|
||||
|
||||
@@ -79,7 +81,11 @@ class PageStorage extends FolderStorage
|
||||
$path = $this->getPathFromKey($key);
|
||||
$file = $this->getFile($path);
|
||||
try {
|
||||
$frontmatter = $file->frontmatter();
|
||||
if ($file instanceof MarkdownFile) {
|
||||
$frontmatter = $file->frontmatter();
|
||||
} else {
|
||||
$frontmatter = $file->raw();
|
||||
}
|
||||
} catch (\RuntimeException $e) {
|
||||
$frontmatter = 'ERROR: ' . $e->getMessage();
|
||||
}
|
||||
|
||||
@@ -64,6 +64,7 @@ class Page implements PageInterface
|
||||
protected $redirect;
|
||||
protected $external_url;
|
||||
protected $items;
|
||||
/** @var \stdClass */
|
||||
protected $header;
|
||||
protected $frontmatter;
|
||||
protected $language;
|
||||
|
||||
@@ -24,7 +24,6 @@ use Grav\Common\Uri;
|
||||
use Grav\Common\Utils;
|
||||
use Grav\Framework\Flex\Flex;
|
||||
use Grav\Framework\Flex\FlexDirectory;
|
||||
use Grav\Framework\Flex\Interfaces\FlexObjectInterface;
|
||||
use Grav\Framework\Flex\Interfaces\FlexTranslateInterface;
|
||||
use Grav\Plugin\Admin;
|
||||
use RocketTheme\Toolbox\Event\Event;
|
||||
@@ -38,10 +37,10 @@ class Pages
|
||||
/** @var Grav */
|
||||
protected $grav;
|
||||
|
||||
/** @var FlexDirectory */
|
||||
/** @var FlexDirectory|null */
|
||||
private $directory;
|
||||
|
||||
/** @var array|PageInterface[] */
|
||||
/** @var array<PageInterface|string> */
|
||||
protected $instances;
|
||||
|
||||
/** @var array */
|
||||
@@ -85,7 +84,7 @@ class Pages
|
||||
/** @var bool */
|
||||
protected $initialized = false;
|
||||
|
||||
/** @var Types */
|
||||
/** @var Types|null */
|
||||
protected static $types;
|
||||
|
||||
/** @var string|null */
|
||||
@@ -137,7 +136,7 @@ class Pages
|
||||
{
|
||||
if ($path !== null) {
|
||||
$path = trim($path, '/');
|
||||
$this->base = $path ? '/' . $path : null;
|
||||
$this->base = $path ? '/' . $path : '';
|
||||
$this->baseRoute = [];
|
||||
}
|
||||
|
||||
@@ -295,16 +294,15 @@ class Pages
|
||||
*/
|
||||
public function instances()
|
||||
{
|
||||
if (!$this->directory) {
|
||||
return $this->instances;
|
||||
}
|
||||
|
||||
$list = [];
|
||||
foreach ($this->instances as $path => $instance) {
|
||||
if (!$instance instanceof PageInterface) {
|
||||
if (is_string($instance) && $this->directory) {
|
||||
/** @var PageInterface $instance */
|
||||
$instance = $this->directory->getObject($instance, 'flex_key');
|
||||
}
|
||||
$list[$path] = $instance;
|
||||
if ($instance instanceof PageInterface) {
|
||||
$list[$path] = $instance;
|
||||
}
|
||||
}
|
||||
|
||||
return $list;
|
||||
@@ -333,9 +331,9 @@ class Pages
|
||||
$this->instances[$path] = $page;
|
||||
}
|
||||
$route = $page->route($route);
|
||||
if ($page->parent()) {
|
||||
$parentPath = $page->parent()->path() ?? '';
|
||||
$this->children[$parentPath][$path] = ['slug' => $page->slug()];
|
||||
$parent = $page->parent();
|
||||
if ($parent) {
|
||||
$this->children[$parent->path() ?? ''][$path] = ['slug' => $page->slug()];
|
||||
}
|
||||
$this->routes[$route] = $path;
|
||||
|
||||
@@ -374,7 +372,7 @@ class Pages
|
||||
$uri = $this->grav['uri'];
|
||||
foreach ($context['taxonomies'] as $taxonomy) {
|
||||
$param = $uri->param(rawurlencode($taxonomy));
|
||||
$items = $param ? explode(',', $param) : [];
|
||||
$items = is_string($param) ? explode(',', $param) : [];
|
||||
foreach ($items as $item) {
|
||||
$params['taxonomies'][$taxonomy][] = htmlspecialchars_decode(rawurldecode($item), ENT_QUOTES);
|
||||
}
|
||||
@@ -641,6 +639,10 @@ class Pages
|
||||
}
|
||||
|
||||
$path = $page->path();
|
||||
if (null === $path) {
|
||||
return [];
|
||||
}
|
||||
|
||||
$children = $this->children[$path] ?? [];
|
||||
|
||||
if (!$children) {
|
||||
@@ -662,7 +664,7 @@ class Pages
|
||||
|
||||
/**
|
||||
* @param Collection $collection
|
||||
* @param string|int $orderBy
|
||||
* @param string $orderBy
|
||||
* @param string $orderDir
|
||||
* @param array|null $orderManual
|
||||
* @param int|null $sort_flags
|
||||
@@ -696,19 +698,25 @@ class Pages
|
||||
*
|
||||
* @param string $path The filesystem full path of the page
|
||||
*
|
||||
* @return PageInterface
|
||||
* @throws \Exception
|
||||
* @return PageInterface|null
|
||||
* @throws \RuntimeException
|
||||
*/
|
||||
public function get($path)
|
||||
{
|
||||
$instance = $this->instances[(string)$path] ?? null;
|
||||
|
||||
if (\is_string($instance)) {
|
||||
$instance = $this->directory ? $this->directory->getObject($instance, 'flex_key') : null;
|
||||
if (method_exists($instance, 'initialize') && $this->grav['config']->get('system.pages.events.page')) {
|
||||
if ($instance && method_exists($instance, 'initialize') && $this->grav['config']->get('system.pages.events.page')) {
|
||||
$instance->initialize();
|
||||
}
|
||||
}
|
||||
if ($instance && !$instance instanceof PageInterface) {
|
||||
|
||||
if (null === $instance) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (!$instance instanceof PageInterface) {
|
||||
throw new \RuntimeException('Routing failed on unknown type', 500);
|
||||
}
|
||||
|
||||
@@ -808,10 +816,12 @@ class Pages
|
||||
$route = urldecode($route);
|
||||
|
||||
// Fetch page if there's a defined route to it.
|
||||
$page = isset($this->routes[$route]) ? $this->get($this->routes[$route]) : null;
|
||||
$path = $this->routes[$route] ?? null;
|
||||
$page = null !== $path ? $this->get($path) : null;
|
||||
// Try without trailing slash
|
||||
if (!$page && Utils::endsWith($route, '/')) {
|
||||
$page = isset($this->routes[rtrim($route, '/')]) ? $this->get($this->routes[rtrim($route, '/')]) : null;
|
||||
$path = $this->routes[rtrim($route, '/')] ?? null;
|
||||
$page = null !== $path ? $this->get($path) : null;
|
||||
}
|
||||
|
||||
// Are we in the admin? this is important!
|
||||
@@ -825,7 +835,7 @@ class Pages
|
||||
}
|
||||
|
||||
// fall back and check site based redirects
|
||||
if (!$page || ($page && !$page->routable())) {
|
||||
if (!$page || !$page->routable()) {
|
||||
// Redirect to the first child (placeholder page)
|
||||
if ($redirect && $page && count($children = $page->children()->visible()) > 0) {
|
||||
$this->grav->redirectLangSafe($children->first()->route());
|
||||
@@ -839,7 +849,6 @@ class Pages
|
||||
if ($site_route) {
|
||||
$page = $this->dispatch($site_route, $all, $redirect);
|
||||
} else {
|
||||
|
||||
/** @var Uri $uri */
|
||||
$uri = $this->grav['uri'];
|
||||
/** @var \Grav\Framework\Uri\Uri $source_url */
|
||||
@@ -849,10 +858,12 @@ class Pages
|
||||
$site_redirects = $config->get('site.redirects');
|
||||
if (is_array($site_redirects)) {
|
||||
foreach ((array)$site_redirects as $pattern => $replace) {
|
||||
$pattern = '#^' . str_replace('/', '\/', ltrim($pattern, '^')) . '#';
|
||||
$pattern = ltrim($pattern, '^');
|
||||
$pattern = '#^' . str_replace('/', '\/', $pattern) . '#';
|
||||
try {
|
||||
/** @var string $found */
|
||||
$found = preg_replace($pattern, $replace, $source_url);
|
||||
if ($found !== $source_url) {
|
||||
if ($found && $found !== $source_url) {
|
||||
$this->grav->redirectLangSafe($found);
|
||||
}
|
||||
} catch (ErrorException $e) {
|
||||
@@ -867,8 +878,9 @@ class Pages
|
||||
foreach ((array)$site_routes as $pattern => $replace) {
|
||||
$pattern = '#^' . str_replace('/', '\/', ltrim($pattern, '^')) . '#';
|
||||
try {
|
||||
/** @var string $found */
|
||||
$found = preg_replace($pattern, $replace, $source_url);
|
||||
if ($found !== $source_url) {
|
||||
if ($found && $found !== $source_url) {
|
||||
$page = $this->dispatch($found, $all, $redirect);
|
||||
}
|
||||
} catch (ErrorException $e) {
|
||||
@@ -887,13 +899,20 @@ class Pages
|
||||
* Get root page.
|
||||
*
|
||||
* @return PageInterface
|
||||
* @throws \RuntimeException
|
||||
*/
|
||||
public function root()
|
||||
{
|
||||
/** @var UniformResourceLocator $locator */
|
||||
$locator = $this->grav['locator'];
|
||||
|
||||
return $this->get(rtrim($locator->findResource('page://'), '/'));
|
||||
$path = $locator->findResource('page://');
|
||||
$root = is_string($path) ? $this->get(rtrim($path, '/')) : null;
|
||||
if (null === $root) {
|
||||
throw new \RuntimeException('Internal error');
|
||||
}
|
||||
|
||||
return $root;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -928,7 +947,7 @@ class Pages
|
||||
*
|
||||
* @param PageInterface $current
|
||||
*
|
||||
* @return \Grav\Common\Page\Collection
|
||||
* @return Collection
|
||||
*/
|
||||
public function all(PageInterface $current = null)
|
||||
{
|
||||
@@ -1053,23 +1072,23 @@ class Pages
|
||||
*/
|
||||
public static function getTypes()
|
||||
{
|
||||
if (!self::$types) {
|
||||
if (null === self::$types) {
|
||||
$grav = Grav::instance();
|
||||
|
||||
$scanBlueprintsAndTemplates = function () use ($grav) {
|
||||
$scanBlueprintsAndTemplates = static function (Types $types) use ($grav) {
|
||||
// Scan blueprints
|
||||
$event = new Event();
|
||||
$event->types = self::$types;
|
||||
$event->types = $types;
|
||||
$grav->fireEvent('onGetPageBlueprints', $event);
|
||||
|
||||
self::$types->scanBlueprints('theme://blueprints/');
|
||||
$types->scanBlueprints('theme://blueprints/');
|
||||
|
||||
// Scan templates
|
||||
$event = new Event();
|
||||
$event->types = self::$types;
|
||||
$event->types = $types;
|
||||
$grav->fireEvent('onGetPageTemplates', $event);
|
||||
|
||||
self::$types->scanTemplates('theme://templates/');
|
||||
$types->scanTemplates('theme://templates/');
|
||||
};
|
||||
|
||||
if ($grav['config']->get('system.cache.enabled')) {
|
||||
@@ -1078,21 +1097,21 @@ class Pages
|
||||
|
||||
// Use cached types if possible.
|
||||
$types_cache_id = md5('types');
|
||||
self::$types = $cache->fetch($types_cache_id);
|
||||
$types = $cache->fetch($types_cache_id);
|
||||
|
||||
if (!self::$types) {
|
||||
self::$types = new Types();
|
||||
$scanBlueprintsAndTemplates();
|
||||
$cache->save($types_cache_id, self::$types);
|
||||
if (!$types instanceof Types) {
|
||||
$types = new Types();
|
||||
$scanBlueprintsAndTemplates($types);
|
||||
$cache->save($types_cache_id, $types);
|
||||
}
|
||||
} else {
|
||||
self::$types = new Types();
|
||||
$scanBlueprintsAndTemplates();
|
||||
$types = new Types();
|
||||
$scanBlueprintsAndTemplates($types);
|
||||
}
|
||||
|
||||
// Register custom paths to the locator.
|
||||
$locator = $grav['locator'];
|
||||
foreach (self::$types as $type => $paths) {
|
||||
foreach ($types as $type => $paths) {
|
||||
foreach ($paths as $k => $path) {
|
||||
if (strpos($path, 'blueprints://') === 0) {
|
||||
unset($paths[$k]);
|
||||
@@ -1102,6 +1121,8 @@ class Pages
|
||||
$locator->addPath('blueprints', "pages/$type.yaml", $paths);
|
||||
}
|
||||
}
|
||||
|
||||
self::$types = $types;
|
||||
}
|
||||
|
||||
return self::$types;
|
||||
@@ -1142,7 +1163,7 @@ class Pages
|
||||
/** @var Admin $admin */
|
||||
$admin = Grav::instance()['admin'];
|
||||
|
||||
/** @var PageInterface $page */
|
||||
/** @var PageInterface|null $page */
|
||||
$page = $admin->page();
|
||||
|
||||
$type = $page && $page->modular() ? 'modular' : 'standard';
|
||||
@@ -1167,7 +1188,7 @@ class Pages
|
||||
{
|
||||
$accessLevels = [];
|
||||
foreach ($this->all() as $page) {
|
||||
if ($page && isset($page->header()->access)) {
|
||||
if ($page instanceof PageInterface && isset($page->header()->access)) {
|
||||
if (\is_array($page->header()->access)) {
|
||||
foreach ($page->header()->access as $index => $accessLevel) {
|
||||
if (\is_array($accessLevel)) {
|
||||
@@ -1292,6 +1313,7 @@ class Pages
|
||||
$page->routable(true);
|
||||
$page->content('## Please install **Flex Objects** plugin. It is required to edit **Flex Pages**.');
|
||||
|
||||
/** @var Header $header */
|
||||
$header = $page->header();
|
||||
$menu = $directory->getConfig('admin.menu.list');
|
||||
$header->access = $menu['authorize'] ?? ['admin.pages', 'admin.super'];
|
||||
@@ -1321,20 +1343,18 @@ class Pages
|
||||
$debugger->startTimer('build-pages', 'Init frontend routes');
|
||||
|
||||
if ($this->directory) {
|
||||
$this->buildFlexPages();
|
||||
$this->buildFlexPages($this->directory);
|
||||
} else {
|
||||
$this->buildRegularPages();
|
||||
}
|
||||
$debugger->stopTimer('build-pages');
|
||||
}
|
||||
|
||||
protected function buildFlexPages()
|
||||
protected function buildFlexPages(FlexDirectory $directory)
|
||||
{
|
||||
/** @var Config $config */
|
||||
$config = $this->grav['config'];
|
||||
|
||||
$directory = $this->directory;
|
||||
|
||||
// TODO: right now we are just emulating normal pages, it is inefficient and bad... but works!
|
||||
$collection = $directory->getIndex();
|
||||
$cache = $directory->getCache('index');
|
||||
@@ -1370,10 +1390,13 @@ class Pages
|
||||
|
||||
/**
|
||||
* @var string $key
|
||||
* @var PageInterface|FlexObjectInterface $page
|
||||
* @var PageInterface $page
|
||||
*/
|
||||
foreach ($collection as $key => $page) {
|
||||
$path = $page->path();
|
||||
if (null === $path) {
|
||||
throw new \RuntimeException('Internal error');
|
||||
}
|
||||
|
||||
if ($page instanceof FlexTranslateInterface) {
|
||||
$page = $page && $page->hasTranslation() ? $page->getTranslation() : null;
|
||||
@@ -1435,12 +1458,16 @@ class Pages
|
||||
|
||||
/** @var UniformResourceLocator $locator */
|
||||
$locator = $grav['locator'];
|
||||
$path = $locator->findResource('page://');
|
||||
if (!is_string($path)) {
|
||||
throw new \RuntimeException('Internal Error');
|
||||
}
|
||||
|
||||
/** @var Config $config */
|
||||
$config = $grav['config'];
|
||||
|
||||
$page = new Page();
|
||||
$page->path($locator->findResource('page://'));
|
||||
$page->path($path);
|
||||
$page->orderDir($config->get('system.pages.order.dir'));
|
||||
$page->orderBy($config->get('system.pages.order.by'));
|
||||
$page->modified(0);
|
||||
@@ -1460,6 +1487,9 @@ class Pages
|
||||
$locator = $this->grav['locator'];
|
||||
|
||||
$pages_dir = $locator->findResource('page://');
|
||||
if (!is_string($pages_dir)) {
|
||||
throw new \RuntimeException('Internal Error');
|
||||
}
|
||||
|
||||
if ($config->get('system.cache.enabled')) {
|
||||
/** @var Language $language */
|
||||
@@ -1689,7 +1719,7 @@ class Pages
|
||||
|
||||
// Override the modified and ID so that it takes the latest change into account
|
||||
$page->modified($last_modified);
|
||||
$page->id($last_modified . md5($page->filePath()));
|
||||
$page->id($last_modified . md5($page->filePath() ?? ''));
|
||||
|
||||
// Sort based on Defaults or Page Overridden sort order
|
||||
$this->children[$page->path()] = $this->sort($page);
|
||||
@@ -1708,7 +1738,7 @@ class Pages
|
||||
// Get the home route
|
||||
$home = self::resetHomeRoute();
|
||||
// Build routes and taxonomy map.
|
||||
/** @var PageInterface $page */
|
||||
/** @var PageInterface|string $page */
|
||||
foreach ($this->instances as $path => $page) {
|
||||
if (\is_string($page)) {
|
||||
$page = $this->get($path);
|
||||
@@ -1721,9 +1751,13 @@ class Pages
|
||||
// process taxonomy
|
||||
$taxonomy->addTaxonomy($page);
|
||||
|
||||
$page_path = $page->path();
|
||||
if (null === $page_path) {
|
||||
throw new \RuntimeException('Internal Error');
|
||||
}
|
||||
|
||||
$route = $page->route();
|
||||
$raw_route = $page->rawRoute();
|
||||
$page_path = $page->path();
|
||||
|
||||
// add regular route
|
||||
$this->routes[$route] = $page_path;
|
||||
@@ -1751,8 +1785,11 @@ class Pages
|
||||
// Alias and set default route to home page.
|
||||
$homeRoute = "/{$home}";
|
||||
if ($home && isset($this->routes[$homeRoute])) {
|
||||
$this->routes['/'] = $this->routes[$homeRoute];
|
||||
$this->get($this->routes[$homeRoute])->route('/');
|
||||
$home = $this->get($this->routes[$homeRoute]);
|
||||
if ($home) {
|
||||
$this->routes['/'] = $this->routes[$homeRoute];
|
||||
$home->route('/');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1769,15 +1806,14 @@ class Pages
|
||||
protected function buildSort($path, array $pages, $order_by = 'default', $manual = null, $sort_flags = null)
|
||||
{
|
||||
$list = [];
|
||||
$header_default = null;
|
||||
$header_query = null;
|
||||
$header_default = null;
|
||||
|
||||
// do this header query work only once
|
||||
if (strpos($order_by, 'header.') === 0) {
|
||||
$header_query = explode('|', str_replace('header.', '', $order_by));
|
||||
if (isset($header_query[1])) {
|
||||
$header_default = $header_query[1];
|
||||
}
|
||||
$query = explode('|', str_replace('header.', '', $order_by), 2);
|
||||
$header_query = array_shift($query);
|
||||
$header_default = array_shift($query);
|
||||
}
|
||||
|
||||
foreach ($pages as $key => $info) {
|
||||
@@ -1815,12 +1851,12 @@ class Pages
|
||||
case 'folder':
|
||||
$list[$key] = $child->folder();
|
||||
break;
|
||||
case (is_string($header_query[0])):
|
||||
case (is_string($header_query)):
|
||||
$child_header = $child->header();
|
||||
if (!$child_header instanceof Header) {
|
||||
$child_header = new Header((array)$child_header);
|
||||
}
|
||||
$header_value = $child_header->get($header_query[0]);
|
||||
$header_value = $child_header->get($header_query);
|
||||
if (is_array($header_value)) {
|
||||
$list[$key] = implode(',', $header_value);
|
||||
} elseif ($header_value) {
|
||||
@@ -1848,13 +1884,16 @@ class Pages
|
||||
} else {
|
||||
// else just sort the list according to specified key
|
||||
if (extension_loaded('intl') && $this->grav['config']->get('system.intl_enabled')) {
|
||||
$locale = setlocale(LC_COLLATE, 0); //`setlocale` with a 0 param returns the current locale set
|
||||
$locale = setlocale(LC_COLLATE, '0'); //`setlocale` with a '0' param returns the current locale set
|
||||
$col = Collator::create($locale);
|
||||
if ($col) {
|
||||
if (($sort_flags & SORT_NATURAL) === SORT_NATURAL) {
|
||||
$list = preg_replace_callback('~([0-9]+)\.~', function ($number) {
|
||||
$list = preg_replace_callback('~([0-9]+)\.~', static function ($number) {
|
||||
return sprintf('%032d.', $number[0]);
|
||||
}, $list);
|
||||
if (!is_array($list)) {
|
||||
throw new \RuntimeException('Internal Error');
|
||||
}
|
||||
|
||||
$list_vals = array_values($list);
|
||||
if (is_numeric(array_shift($list_vals))) {
|
||||
|
||||
@@ -23,6 +23,7 @@ use Twig\Environment;
|
||||
use Twig\Error\LoaderError;
|
||||
use Twig\Extension\CoreExtension;
|
||||
use Twig\Extension\DebugExtension;
|
||||
use Twig\Extension\StringLoaderExtension;
|
||||
use Twig\Loader\ArrayLoader;
|
||||
use Twig\Loader\ChainLoader;
|
||||
use Twig\Loader\FilesystemLoader;
|
||||
@@ -198,6 +199,7 @@ class Twig
|
||||
}
|
||||
$this->twig->addExtension(new TwigExtension());
|
||||
$this->twig->addExtension(new DeferredExtension());
|
||||
$this->twig->addExtension(new StringLoaderExtension());
|
||||
|
||||
$this->profile = new \Twig\Profiler\Profile();
|
||||
$this->twig->addExtension(new \Twig\Extension\ProfilerExtension($this->profile));
|
||||
|
||||
@@ -301,7 +301,7 @@ class Uri
|
||||
* Get URI parameter.
|
||||
*
|
||||
* @param string $id
|
||||
* @param bool $default
|
||||
* @param string|bool|null $default
|
||||
*
|
||||
* @return bool|string
|
||||
*/
|
||||
|
||||
@@ -48,6 +48,16 @@ abstract class AbstractFormatter implements FileFormatterInterface
|
||||
$this->doUnserialize(unserialize($serialized, ['allowed_classes' => false]));
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getMimeType(): string
|
||||
{
|
||||
$mime = $this->getConfig('mime');
|
||||
|
||||
return \is_string($mime) ? $mime : 'application/octet-stream';
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
* @see FileFormatterInterface::getDefaultFileExtension()
|
||||
|
||||
@@ -23,7 +23,8 @@ class CsvFormatter extends AbstractFormatter
|
||||
{
|
||||
$config += [
|
||||
'file_extension' => ['.csv', '.tsv'],
|
||||
'delimiter' => ','
|
||||
'delimiter' => ',',
|
||||
'mime' => 'text/x-csv'
|
||||
];
|
||||
|
||||
parent::__construct($config);
|
||||
|
||||
@@ -26,6 +26,12 @@ namespace Grav\Framework\File\Interfaces;
|
||||
*/
|
||||
interface FileFormatterInterface extends \Serializable
|
||||
{
|
||||
/**
|
||||
* @return string
|
||||
* @since 1.7
|
||||
*/
|
||||
public function getMimeType(): string;
|
||||
|
||||
/**
|
||||
* Get default file extension from current formatter (with dot).
|
||||
*
|
||||
|
||||
@@ -300,6 +300,10 @@ class FlexCollection extends ObjectCollection implements FlexCollectionInterface
|
||||
return $this->getFlexDirectory()->getIndex($this->getKeys(), $this->getKeyField());
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritdoc}
|
||||
* @see FlexCollectionInterface::getCollection()
|
||||
*/
|
||||
public function getCollection()
|
||||
{
|
||||
return $this;
|
||||
|
||||
@@ -122,6 +122,13 @@ interface FlexCollectionInterface extends FlexCommonInterface, ObjectCollectionI
|
||||
*/
|
||||
public function getIndex();
|
||||
|
||||
/**
|
||||
* Load all the objects into memory,
|
||||
*
|
||||
* @return FlexCollectionInterface
|
||||
*/
|
||||
public function getCollection();
|
||||
|
||||
/**
|
||||
* Get metadata associated to the object
|
||||
*
|
||||
|
||||
@@ -29,14 +29,15 @@ class Install
|
||||
'7.3' => '7.3.1',
|
||||
'7.2' => '7.2.0',
|
||||
'7.1' => '7.1.3',
|
||||
'' => '7.2.14'
|
||||
'' => '7.3.9'
|
||||
]
|
||||
],
|
||||
'grav' => [
|
||||
'name' => 'Grav',
|
||||
'versions' => [
|
||||
'1.6' => '1.6.0',
|
||||
'1.5' => '1.5.0',
|
||||
'' => '1.5.7'
|
||||
'' => '1.6.16'
|
||||
]
|
||||
],
|
||||
'plugins' => [
|
||||
@@ -44,32 +45,36 @@ class Install
|
||||
'name' => 'Admin',
|
||||
'optional' => true,
|
||||
'versions' => [
|
||||
'1.9' => '1.9.0',
|
||||
'1.8' => '1.8.0',
|
||||
'' => '1.8.16'
|
||||
'' => '1.9.10'
|
||||
]
|
||||
],
|
||||
'email' => [
|
||||
'name' => 'Email',
|
||||
'optional' => true,
|
||||
'versions' => [
|
||||
'3.0' => '3.0.0',
|
||||
'2.7' => '2.7.0',
|
||||
'' => '2.7.2'
|
||||
'' => '3.0.3'
|
||||
]
|
||||
],
|
||||
'form' => [
|
||||
'name' => 'Form',
|
||||
'optional' => true,
|
||||
'versions' => [
|
||||
'3.0' => '3.0.0',
|
||||
'2.16' => '2.16.0',
|
||||
'' => '2.16.4'
|
||||
'' => '3.0.9'
|
||||
]
|
||||
],
|
||||
'login' => [
|
||||
'name' => 'Login',
|
||||
'optional' => true,
|
||||
'versions' => [
|
||||
'3.0' => '3.0.0',
|
||||
'2.8' => '2.8.0',
|
||||
'' => '2.8.3'
|
||||
'' => '3.0.4'
|
||||
]
|
||||
],
|
||||
]
|
||||
@@ -157,9 +162,10 @@ class Install
|
||||
public function prepare(): void
|
||||
{
|
||||
// Locate the new Grav update and the target site from the filesystem.
|
||||
$location = dirname(realpath(__DIR__), 4);
|
||||
$target = dirname(realpath(GRAV_ROOT . '/index.php'));
|
||||
if ($location === $target) {
|
||||
$location = realpath(__DIR__);
|
||||
$target = realpath(GRAV_ROOT . '/index.php');
|
||||
|
||||
if ($location && $target && dirname($location, 4) === dirname($target)) {
|
||||
// We cannot copy files into themselves, abort!
|
||||
throw new \RuntimeException('Grav has already been installed here!', 400);
|
||||
}
|
||||
|
||||
@@ -17,6 +17,7 @@ parameters:
|
||||
- Grav\Common\GPM\Common\Package
|
||||
- Grav\Common\GPM\Local\Package
|
||||
- Grav\Common\GPM\Remote\Package
|
||||
- Grav\Common\Page\Header
|
||||
- Grav\Common\Session
|
||||
ignoreErrors:
|
||||
|
||||
|
||||
Reference in New Issue
Block a user