Upgrade to 3.9.2
This commit is contained in:
@@ -482,28 +482,23 @@ class App
|
||||
|
||||
/**
|
||||
* Try to find a controller by name
|
||||
*
|
||||
* @param string $name
|
||||
* @param string $contentType
|
||||
* @return \Kirby\Toolkit\Controller|null
|
||||
*/
|
||||
protected function controllerLookup(string $name, string $contentType = 'html')
|
||||
protected function controllerLookup(string $name, string $contentType = 'html'): Controller|null
|
||||
{
|
||||
if ($contentType !== null && $contentType !== 'html') {
|
||||
$name .= '.' . $contentType;
|
||||
}
|
||||
|
||||
// controller on disk
|
||||
if ($controller = Controller::load($this->root('controllers') . '/' . $name . '.php')) {
|
||||
// controller from site root
|
||||
$controller = Controller::load($this->root('controllers') . '/' . $name . '.php');
|
||||
// controller from extension
|
||||
$controller ??= $this->extension('controllers', $name);
|
||||
|
||||
if ($controller instanceof Controller) {
|
||||
return $controller;
|
||||
}
|
||||
|
||||
// registry controller
|
||||
if ($controller = $this->extension('controllers', $name)) {
|
||||
if ($controller instanceof Controller) {
|
||||
return $controller;
|
||||
}
|
||||
|
||||
if ($controller !== null) {
|
||||
return new Controller($controller);
|
||||
}
|
||||
|
||||
|
@@ -4,6 +4,7 @@ namespace Kirby\Cms;
|
||||
|
||||
use Closure;
|
||||
use Kirby\Exception\DuplicateException;
|
||||
use Kirby\Filesystem\Asset;
|
||||
use Kirby\Filesystem\Dir;
|
||||
use Kirby\Filesystem\F;
|
||||
use Kirby\Filesystem\Mime;
|
||||
@@ -45,6 +46,7 @@ trait AppPlugins
|
||||
// other plugin types
|
||||
'api' => [],
|
||||
'areas' => [],
|
||||
'assetMethods' => [],
|
||||
'authChallenges' => [],
|
||||
'blockMethods' => [],
|
||||
'blockModels' => [],
|
||||
@@ -147,6 +149,17 @@ trait AppPlugins
|
||||
return $this->extensions['areas'];
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers additional asset methods
|
||||
*
|
||||
* @param array $methods
|
||||
* @return array
|
||||
*/
|
||||
protected function extendAssetMethods(array $methods): array
|
||||
{
|
||||
return $this->extensions['assetMethods'] = Asset::$methods = array_merge(Asset::$methods, $methods);
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers additional authentication challenges
|
||||
*
|
||||
|
@@ -73,6 +73,13 @@ class Block extends Item
|
||||
{
|
||||
parent::__construct($params);
|
||||
|
||||
// @deprecated import old builder format
|
||||
// @todo block.converter remove eventually
|
||||
// @codeCoverageIgnoreStart
|
||||
$params = BlockConverter::builderBlock($params);
|
||||
$params = BlockConverter::editorBlock($params);
|
||||
// @codeCoverageIgnoreEnd
|
||||
|
||||
if (isset($params['type']) === false) {
|
||||
throw new InvalidArgumentException('The block type is missing');
|
||||
}
|
||||
|
285
kirby/src/Cms/BlockConverter.php
Normal file
285
kirby/src/Cms/BlockConverter.php
Normal file
@@ -0,0 +1,285 @@
|
||||
<?php
|
||||
|
||||
namespace Kirby\Cms;
|
||||
|
||||
/**
|
||||
* Converts the data from the old builder and editor fields
|
||||
* to the format supported by the new block field.
|
||||
* @since 3.9.0
|
||||
* @deprecated
|
||||
*
|
||||
* @todo block.converter remove eventually
|
||||
* @codeCoverageIgnore
|
||||
*
|
||||
* @package Kirby Cms
|
||||
* @author Bastian Allgeier <bastian@getkirby.com>
|
||||
* @link https://getkirby.com
|
||||
* @copyright Bastian Allgeier GmbH
|
||||
* @license https://getkirby.com/license
|
||||
*/
|
||||
class BlockConverter
|
||||
{
|
||||
public static function builderBlock(array $params): array
|
||||
{
|
||||
if (isset($params['_key']) === false) {
|
||||
return $params;
|
||||
}
|
||||
|
||||
$params['type'] = $params['_key'];
|
||||
$params['content'] = $params;
|
||||
unset($params['_uid']);
|
||||
|
||||
return $params;
|
||||
}
|
||||
|
||||
public static function editorBlock(array $params): array
|
||||
{
|
||||
if (static::isEditorBlock($params) === false) {
|
||||
return $params;
|
||||
}
|
||||
|
||||
$method = 'editor' . $params['type'];
|
||||
|
||||
if (method_exists(static::class, $method) === true) {
|
||||
$params = static::$method($params);
|
||||
} else {
|
||||
$params = static::editorCustom($params);
|
||||
}
|
||||
|
||||
return $params;
|
||||
}
|
||||
|
||||
public static function editorBlocks(array $blocks = []): array
|
||||
{
|
||||
if (empty($blocks) === true) {
|
||||
return $blocks;
|
||||
}
|
||||
|
||||
if (static::isEditorBlock($blocks[0]) === false) {
|
||||
return $blocks;
|
||||
}
|
||||
|
||||
$list = [];
|
||||
$listStart = null;
|
||||
|
||||
foreach ($blocks as $index => $block) {
|
||||
if (in_array($block['type'], ['ul', 'ol']) === true) {
|
||||
$prev = $blocks[$index-1] ?? null;
|
||||
$next = $blocks[$index+1] ?? null;
|
||||
|
||||
// new list starts here
|
||||
if (!$prev || $prev['type'] !== $block['type']) {
|
||||
$listStart = $index;
|
||||
}
|
||||
|
||||
// add the block to the list
|
||||
$list[] = $block;
|
||||
|
||||
// list ends here
|
||||
if (!$next || $next['type'] !== $block['type']) {
|
||||
$blocks[$listStart] = [
|
||||
'content' => [
|
||||
'text' =>
|
||||
'<' . $block['type'] . '>' .
|
||||
implode(array_map(
|
||||
fn ($item) => '<li>' . $item['content'] . '</li>',
|
||||
$list
|
||||
)) .
|
||||
'</' . $block['type'] . '>',
|
||||
],
|
||||
'type' => 'list'
|
||||
];
|
||||
|
||||
$start = $listStart + 1;
|
||||
$end = $listStart + count($list);
|
||||
|
||||
for ($x = $start; $x <= $end; $x++) {
|
||||
$blocks[$x] = false;
|
||||
}
|
||||
|
||||
$listStart = null;
|
||||
$list = [];
|
||||
}
|
||||
} else {
|
||||
$blocks[$index] = static::editorBlock($block);
|
||||
}
|
||||
}
|
||||
|
||||
return array_filter($blocks);
|
||||
}
|
||||
|
||||
public static function editorBlockquote(array $params): array
|
||||
{
|
||||
return [
|
||||
'content' => [
|
||||
'text' => $params['content']
|
||||
],
|
||||
'type' => 'quote'
|
||||
];
|
||||
}
|
||||
|
||||
public static function editorCode(array $params): array
|
||||
{
|
||||
return [
|
||||
'content' => [
|
||||
'language' => $params['attrs']['language'] ?? null,
|
||||
'code' => $params['content']
|
||||
],
|
||||
'type' => 'code'
|
||||
];
|
||||
}
|
||||
|
||||
public static function editorCustom(array $params): array
|
||||
{
|
||||
return [
|
||||
'content' => array_merge(
|
||||
$params['attrs'] ?? [],
|
||||
[
|
||||
'body' => $params['content'] ?? null
|
||||
]
|
||||
),
|
||||
'type' => $params['type'] ?? 'unknown'
|
||||
];
|
||||
}
|
||||
|
||||
public static function editorH1(array $params): array
|
||||
{
|
||||
return static::editorHeading($params, 'h1');
|
||||
}
|
||||
|
||||
public static function editorH2(array $params): array
|
||||
{
|
||||
return static::editorHeading($params, 'h2');
|
||||
}
|
||||
|
||||
public static function editorH3(array $params): array
|
||||
{
|
||||
return static::editorHeading($params, 'h3');
|
||||
}
|
||||
|
||||
public static function editorH4(array $params): array
|
||||
{
|
||||
return static::editorHeading($params, 'h4');
|
||||
}
|
||||
|
||||
public static function editorH5(array $params): array
|
||||
{
|
||||
return static::editorHeading($params, 'h5');
|
||||
}
|
||||
|
||||
public static function editorH6(array $params): array
|
||||
{
|
||||
return static::editorHeading($params, 'h6');
|
||||
}
|
||||
|
||||
public static function editorHr(array $params): array
|
||||
{
|
||||
return [
|
||||
'content' => [],
|
||||
'type' => 'line'
|
||||
];
|
||||
}
|
||||
|
||||
public static function editorHeading(array $params, string $level = 'h1'): array
|
||||
{
|
||||
return [
|
||||
'content' => [
|
||||
'level' => $level,
|
||||
'text' => $params['content']
|
||||
],
|
||||
'type' => 'heading'
|
||||
];
|
||||
}
|
||||
|
||||
public static function editorImage(array $params): array
|
||||
{
|
||||
// internal image
|
||||
if (isset($params['attrs']['id']) === true) {
|
||||
return [
|
||||
'content' => [
|
||||
'alt' => $params['attrs']['alt'] ?? null,
|
||||
'caption' => $params['attrs']['caption'] ?? null,
|
||||
'image' => $params['attrs']['id'] ?? $params['attrs']['src'] ?? null,
|
||||
'location' => 'kirby',
|
||||
'ratio' => $params['attrs']['ratio'] ?? null,
|
||||
],
|
||||
'type' => 'image'
|
||||
];
|
||||
}
|
||||
|
||||
return [
|
||||
'content' => [
|
||||
'alt' => $params['attrs']['alt'] ?? null,
|
||||
'caption' => $params['attrs']['caption'] ?? null,
|
||||
'src' => $params['attrs']['src'] ?? null,
|
||||
'location' => 'web',
|
||||
'ratio' => $params['attrs']['ratio'] ?? null,
|
||||
],
|
||||
'type' => 'image'
|
||||
];
|
||||
}
|
||||
|
||||
public static function editorKirbytext(array $params): array
|
||||
{
|
||||
return [
|
||||
'content' => [
|
||||
'text' => $params['content']
|
||||
],
|
||||
'type' => 'markdown'
|
||||
];
|
||||
}
|
||||
|
||||
public static function editorOl(array $params): array
|
||||
{
|
||||
return [
|
||||
'content' => [
|
||||
'text' => $params['content']
|
||||
],
|
||||
'type' => 'list'
|
||||
];
|
||||
}
|
||||
|
||||
public static function editorParagraph(array $params): array
|
||||
{
|
||||
return [
|
||||
'content' => [
|
||||
'text' => '<p>' . $params['content'] . '</p>'
|
||||
],
|
||||
'type' => 'text'
|
||||
];
|
||||
}
|
||||
|
||||
public static function editorUl(array $params): array
|
||||
{
|
||||
return [
|
||||
'content' => [
|
||||
'text' => $params['content']
|
||||
],
|
||||
'type' => 'list'
|
||||
];
|
||||
}
|
||||
|
||||
public static function editorVideo(array $params): array
|
||||
{
|
||||
return [
|
||||
'content' => [
|
||||
'caption' => $params['attrs']['caption'] ?? null,
|
||||
'url' => $params['attrs']['src'] ?? null
|
||||
],
|
||||
'type' => 'video'
|
||||
];
|
||||
}
|
||||
|
||||
public static function isEditorBlock(array $params): bool
|
||||
{
|
||||
if (isset($params['attrs']) === true) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (is_string($params['content'] ?? null) === true) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
@@ -2,9 +2,12 @@
|
||||
|
||||
namespace Kirby\Cms;
|
||||
|
||||
use Exception;
|
||||
use Kirby\Data\Json;
|
||||
use Kirby\Data\Yaml;
|
||||
use Kirby\Parsley\Parsley;
|
||||
use Kirby\Parsley\Schema\Blocks as BlockSchema;
|
||||
use Kirby\Toolkit\A;
|
||||
use Kirby\Toolkit\Str;
|
||||
use Throwable;
|
||||
|
||||
@@ -58,6 +61,12 @@ class Blocks extends Items
|
||||
{
|
||||
$items = static::extractFromLayouts($items);
|
||||
|
||||
// @deprecated old editor format
|
||||
// @todo block.converter remove eventually
|
||||
// @codeCoverageIgnoreStart
|
||||
$items = BlockConverter::editorBlocks($items);
|
||||
// @codeCoverageIgnoreEnd
|
||||
|
||||
return parent::factory($items, $params);
|
||||
}
|
||||
|
||||
@@ -73,8 +82,13 @@ class Blocks extends Items
|
||||
return [];
|
||||
}
|
||||
|
||||
// no columns = no layout
|
||||
if (array_key_exists('columns', $input[0]) === false) {
|
||||
if (
|
||||
// no columns = no layout
|
||||
array_key_exists('columns', $input[0]) === false ||
|
||||
// @deprecated checks if this is a block for the builder plugin
|
||||
// @todo block.converter remove eventually
|
||||
array_key_exists('_key', $input[0]) === true
|
||||
) {
|
||||
return $input;
|
||||
}
|
||||
|
||||
@@ -115,8 +129,33 @@ class Blocks extends Items
|
||||
try {
|
||||
$input = Json::decode((string)$input);
|
||||
} catch (Throwable) {
|
||||
$parser = new Parsley((string)$input, new BlockSchema());
|
||||
$input = $parser->blocks();
|
||||
// @deprecated try to import the old YAML format
|
||||
// @todo block.converter remove eventually
|
||||
// @codeCoverageIgnoreStart
|
||||
try {
|
||||
$yaml = Yaml::decode((string)$input);
|
||||
$first = A::first($yaml);
|
||||
|
||||
// check for valid yaml
|
||||
if (
|
||||
empty($yaml) === true ||
|
||||
(
|
||||
isset($first['_key']) === false &&
|
||||
isset($first['type']) === false
|
||||
)
|
||||
) {
|
||||
throw new Exception('Invalid YAML');
|
||||
} else {
|
||||
$input = $yaml;
|
||||
}
|
||||
} catch (Throwable $e) {
|
||||
// the next 2 lines remain after removing block.converter
|
||||
// @codeCoverageIgnoreEnd
|
||||
$parser = new Parsley((string)$input, new BlockSchema());
|
||||
$input = $parser->blocks();
|
||||
// @codeCoverageIgnoreStart
|
||||
}
|
||||
// @codeCoverageIgnoreEnd
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -179,7 +179,7 @@ class File extends ModelWithContent
|
||||
public function contentFileData(array $data, string $languageCode = null): array
|
||||
{
|
||||
return A::append($data, [
|
||||
'template' => $this->template(),
|
||||
'template' => $data['template'] ?? $this->template(),
|
||||
]);
|
||||
}
|
||||
|
||||
|
@@ -26,6 +26,8 @@ class Item
|
||||
|
||||
public const ITEMS_CLASS = Items::class;
|
||||
|
||||
protected Field|null $field;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
@@ -57,6 +59,7 @@ class Item
|
||||
|
||||
$this->id = $params['id'] ?? Str::uuid();
|
||||
$this->params = $params;
|
||||
$this->field = $params['field'] ?? null;
|
||||
$this->parent = $params['parent'] ?? App::instance()->site();
|
||||
$this->siblings = $params['siblings'] ?? new $siblingsClass();
|
||||
}
|
||||
@@ -72,6 +75,14 @@ class Item
|
||||
return new static($params);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the parent field if known
|
||||
*/
|
||||
public function field(): Field|null
|
||||
{
|
||||
return $this->field;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the unique item id (UUID v4)
|
||||
*
|
||||
|
@@ -19,6 +19,8 @@ class Items extends Collection
|
||||
{
|
||||
public const ITEM_CLASS = Item::class;
|
||||
|
||||
protected Field|null $field;
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
@@ -39,6 +41,7 @@ class Items extends Collection
|
||||
{
|
||||
$this->options = $options;
|
||||
$this->parent = $options['parent'] ?? App::instance()->site();
|
||||
$this->field = $options['field'] ?? null;
|
||||
|
||||
parent::__construct($objects, $this->parent);
|
||||
}
|
||||
@@ -54,6 +57,7 @@ class Items extends Collection
|
||||
public static function factory(array $items = null, array $params = [])
|
||||
{
|
||||
$options = array_merge([
|
||||
'field' => null,
|
||||
'options' => [],
|
||||
'parent' => App::instance()->site(),
|
||||
], $params);
|
||||
@@ -74,6 +78,7 @@ class Items extends Collection
|
||||
continue;
|
||||
}
|
||||
|
||||
$params['field'] = $options['field'];
|
||||
$params['options'] = $options['options'];
|
||||
$params['parent'] = $options['parent'];
|
||||
$params['siblings'] = $collection;
|
||||
@@ -85,6 +90,14 @@ class Items extends Collection
|
||||
return $collection;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the parent field if known
|
||||
*/
|
||||
public function field(): Field|null
|
||||
{
|
||||
return $this->field;
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert the items to an array
|
||||
*
|
||||
|
@@ -56,6 +56,7 @@ class Layout extends Item
|
||||
parent::__construct($params);
|
||||
|
||||
$this->columns = LayoutColumns::factory($params['columns'] ?? [], [
|
||||
'field' => $this->field,
|
||||
'parent' => $this->parent
|
||||
]);
|
||||
|
||||
|
@@ -41,6 +41,7 @@ class LayoutColumn extends Item
|
||||
parent::__construct($params);
|
||||
|
||||
$this->blocks = Blocks::factory($params['blocks'] ?? [], [
|
||||
'field' => $this->field,
|
||||
'parent' => $this->parent
|
||||
]);
|
||||
|
||||
|
@@ -98,6 +98,9 @@ class Layouts extends Items
|
||||
}
|
||||
}
|
||||
|
||||
return Blocks::factory($blocks);
|
||||
return Blocks::factory($blocks, [
|
||||
'field' => $this->field,
|
||||
'parent' => $this->parent
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
@@ -521,9 +521,9 @@ trait PageActions
|
||||
public static function create(array $props)
|
||||
{
|
||||
// clean up the slug
|
||||
$props['slug'] = Str::slug($props['slug'] ?? $props['content']['title'] ?? null);
|
||||
$props['template'] = $props['model'] = strtolower($props['template'] ?? 'default');
|
||||
$props['isDraft'] = ($props['draft'] ?? true);
|
||||
$props['slug'] = Str::slug($props['slug'] ?? $props['content']['title'] ?? null);
|
||||
$props['template'] = $props['model'] = strtolower($props['template'] ?? 'default');
|
||||
$props['isDraft'] ??= $props['draft'] ?? true;
|
||||
|
||||
// make sure that a UUID gets generated and
|
||||
// added to content right away
|
||||
|
@@ -204,7 +204,12 @@ class PageRules
|
||||
]);
|
||||
}
|
||||
|
||||
if (count($page->blueprints()) <= 1) {
|
||||
$blueprints = $page->blueprints();
|
||||
|
||||
if (
|
||||
count($blueprints) <= 1 ||
|
||||
in_array($template, array_column($blueprints, 'name')) === false
|
||||
) {
|
||||
throw new LogicException([
|
||||
'key' => 'page.changeTemplate.invalid',
|
||||
'data' => ['slug' => $page->slug()]
|
||||
|
@@ -154,10 +154,10 @@ class Pages extends Collection
|
||||
*
|
||||
* @param array $pages
|
||||
* @param \Kirby\Cms\Model|null $model
|
||||
* @param bool $draft
|
||||
* @param bool|null $draft
|
||||
* @return static
|
||||
*/
|
||||
public static function factory(array $pages, Model $model = null, bool $draft = false)
|
||||
public static function factory(array $pages, Model $model = null, bool $draft = null)
|
||||
{
|
||||
$model ??= App::instance()->site();
|
||||
$children = new static([], $model);
|
||||
@@ -175,7 +175,7 @@ class Pages extends Collection
|
||||
$props['kirby'] = $kirby;
|
||||
$props['parent'] = $parent;
|
||||
$props['site'] = $site;
|
||||
$props['isDraft'] = $draft;
|
||||
$props['isDraft'] = $draft ?? $props['isDraft'] ?? $props['draft'] ?? false;
|
||||
|
||||
$page = Page::factory($props);
|
||||
|
||||
|
Reference in New Issue
Block a user