Upgrade to 3.9.0

This commit is contained in:
Bastian Allgeier
2023-01-17 14:50:16 +01:00
parent 0ebe0c7b16
commit 6e5c9d1f48
132 changed files with 1664 additions and 1254 deletions

View File

@@ -53,6 +53,10 @@ return [
// panel classes
'panel' => 'Kirby\Panel\Panel',
// template classes
'snippet' => 'Kirby\Template\Snippet',
'slot' => 'Kirby\Template\Slot',
// toolkit classes
'a' => 'Kirby\Toolkit\A',
'c' => 'Kirby\Toolkit\Config',
@@ -73,6 +77,7 @@ return [
'kirby\cms\form' => 'Kirby\Form\Form',
'kirby\cms\kirbytag' => 'Kirby\Text\KirbyTag',
'kirby\cms\kirbytags' => 'Kirby\Text\KirbyTags',
'kirby\cms\template' => 'Kirby\Template\Template',
'kirby\toolkit\dir' => 'Kirby\Filesystem\Dir',
'kirby\toolkit\f' => 'Kirby\Filesystem\F',
'kirby\toolkit\file' => 'Kirby\Filesystem\File',

View File

@@ -35,8 +35,9 @@ return [
$code = $this->user()?->language() ??
$this->kirby()->panelLanguage();
return $this->kirby()->translation($code) ??
$this->kirby()->translation('en');
return
$this->kirby()->translation($code) ??
$this->kirby()->translation('en');
},
'kirbytext' => fn () => $this->kirby()->option('panel.kirbytext') ?? true,
'user' => fn () => $this->user(),

View File

@@ -38,14 +38,17 @@ return [
// move_uploaded_file() not working with unit test
// @codeCoverageIgnoreStart
return $this->upload(function ($source, $filename) use ($path) {
return $this->parent($path)->createFile([
$props = [
'content' => [
'sort' => $this->requestBody('sort')
],
'source' => $source,
'template' => $this->requestBody('template'),
'filename' => $filename
]);
];
// move the source file from the temp dir
return $this->parent($path)->createFile($props, true);
});
// @codeCoverageIgnoreEnd
}
@@ -95,8 +98,9 @@ return [
'pattern' => $pattern . '/files/(:any)',
'method' => 'POST',
'action' => function (string $path, string $filename) {
// move the source file from the temp dir
return $this->upload(
fn ($source) => $this->file($path, $filename)->replace($source)
fn ($source) => $this->file($path, $filename)->replace($source, true)
);
}
],

View File

@@ -4,6 +4,9 @@
/**
* Content Lock Routes
*/
use Kirby\Exception\NotFoundException;
return [
[
'pattern' => '(:all)/lock',
@@ -25,7 +28,11 @@ return [
'pattern' => '(:all)/lock',
'method' => 'DELETE',
'action' => function (string $path) {
return $this->parent($path)->lock()?->remove();
try {
return $this->parent($path)->lock()?->remove();
} catch (NotFoundException) {
return true;
}
}
],
[
@@ -39,7 +46,11 @@ return [
'pattern' => '(:all)/unlock',
'method' => 'DELETE',
'action' => function (string $path) {
return $this->parent($path)->lock()?->resolve();
try {
return $this->parent($path)->lock()?->resolve();
} catch (NotFoundException) {
return true;
}
}
],
];

View File

@@ -82,11 +82,16 @@ return [
$this->user($id)->avatar()?->delete();
return $this->upload(
fn ($source, $filename) => $this->user($id)->createFile([
'filename' => 'profile.' . F::extension($filename),
'template' => 'avatar',
'source' => $source
]),
function ($source, $filename) {
$props = [
'filename' => 'profile.' . F::extension($filename),
'template' => 'avatar',
'source' => $source
];
// move the source file from the temp dir
return $this->user($id)->createFile($props, true);
},
single: true
);
}

View File

@@ -44,10 +44,17 @@ return [
// license registration
'registration' => [
'load' => function () {
$system = App::instance()->system();
return [
'component' => 'k-form-dialog',
'props' => [
'fields' => [
'domain' => [
'type' => 'info',
'theme' => $system->isLocal() ? 'notice' : 'info',
'text' => I18n::template('license.register.' . ($system->isLocal() ? 'local' : 'domain'), ['host' => $system->indexUrl()])
],
'license' => [
'label' => I18n::translate('license.register.label'),
'type' => 'text',
@@ -56,9 +63,7 @@ return [
'placeholder' => 'K3-',
'help' => I18n::translate('license.register.help')
],
'email' => Field::email([
'required' => true
])
'email' => Field::email(['required' => true])
],
'submitButton' => I18n::translate('license.register'),
'value' => [

View File

@@ -5,7 +5,6 @@ use Kirby\Cms\Collection;
use Kirby\Cms\File;
use Kirby\Cms\FileVersion;
use Kirby\Cms\Page;
use Kirby\Cms\Template;
use Kirby\Cms\User;
use Kirby\Data\Data;
use Kirby\Email\PHPMailer as Emailer;
@@ -14,11 +13,12 @@ use Kirby\Filesystem\Filename;
use Kirby\Http\Uri;
use Kirby\Http\Url;
use Kirby\Image\Darkroom;
use Kirby\Template\Snippet;
use Kirby\Template\Template;
use Kirby\Text\Markdown;
use Kirby\Text\SmartyPants;
use Kirby\Toolkit\A;
use Kirby\Toolkit\Str;
use Kirby\Toolkit\Tpl as Snippet;
return [
@@ -142,6 +142,7 @@ return [
* @return \Kirby\Cms\Collection|bool
*/
'search' => function (App $kirby, Collection $collection, string $query = null, $params = []) {
// empty search query
if (empty(trim($query ?? '')) === true) {
return $collection->limit(0);
}
@@ -159,28 +160,31 @@ return [
$options = array_merge($defaults, $params);
$collection = clone $collection;
$searchWords = preg_replace('/(\s)/u', ',', $query);
$searchWords = Str::split($searchWords, ',', $options['minlength']);
$lowerQuery = Str::lower($query);
$exactQuery = $options['words'] ? '(\b' . preg_quote($query) . '\b)' : preg_quote($query);
$words = preg_replace('/(\s)/u', ',', $query);
$words = Str::split($words, ',', $options['minlength']);
$exact = $options['words'] ? '(\b' . preg_quote($query) . '\b)' : preg_quote($query);
$query = Str::lower($query);
if (empty($options['stopwords']) === false) {
$searchWords = array_diff($searchWords, $options['stopwords']);
$words = array_diff($words, $options['stopwords']);
}
$searchWords = array_map(function ($value) use ($options) {
return $options['words'] ? '\b' . preg_quote($value) . '\b' : preg_quote($value);
}, $searchWords);
$words = A::map(
$words,
fn ($value) => $options['words'] ? '\b' . preg_quote($value) . '\b' : preg_quote($value)
);
// returns an empty collection if there is no search word
if (empty($searchWords) === true) {
if (empty($words) === true) {
return $collection->limit(0);
}
$preg = '!(' . implode('|', $searchWords) . ')!i';
$results = $collection->filter(function ($item) use ($query, $preg, $options, $lowerQuery, $exactQuery) {
$data = $item->content()->toArray();
$keys = array_keys($data);
$preg = '!(' . implode('|', $words) . ')!i';
$scores = [];
$results = $collection->filter(function ($item) use ($query, $exact, $preg, $options, &$scores) {
$data = $item->content()->toArray();
$keys = array_keys($data);
$keys[] = 'id';
if ($item instanceof User) {
@@ -200,8 +204,10 @@ return [
$keys = array_intersect($keys, $fields);
}
$item->searchHits = 0;
$item->searchScore = 0;
$scoring = [
'hits' => 0,
'score' => 0
];
foreach ($keys as $key) {
$score = $options['score'][$key] ?? 1;
@@ -210,32 +216,39 @@ return [
$lowerValue = Str::lower($value);
// check for exact matches
if ($lowerQuery == $lowerValue) {
$item->searchScore += 16 * $score;
$item->searchHits += 1;
if ($query == $lowerValue) {
$scoring['score'] += 16 * $score;
$scoring['hits'] += 1;
// check for exact beginning matches
} elseif ($options['words'] === false && Str::startsWith($lowerValue, $lowerQuery) === true) {
$item->searchScore += 8 * $score;
$item->searchHits += 1;
} elseif (
$options['words'] === false &&
Str::startsWith($lowerValue, $query) === true
) {
$scoring['score'] += 8 * $score;
$scoring['hits'] += 1;
// check for exact query matches
} elseif ($matches = preg_match_all('!' . $exactQuery . '!i', $value, $r)) {
$item->searchScore += 2 * $score;
$item->searchHits += $matches;
} elseif ($matches = preg_match_all('!' . $exact . '!i', $value, $r)) {
$scoring['score'] += 2 * $score;
$scoring['hits'] += $matches;
}
// check for any match
if ($matches = preg_match_all($preg, $value, $r)) {
$item->searchHits += $matches;
$item->searchScore += $matches * $score;
$scoring['score'] += $matches * $score;
$scoring['hits'] += $matches;
}
}
return $item->searchHits > 0;
$scores[$item->id()] = $scoring;
return $scoring['hits'] > 0;
});
return $results->sort('searchScore', 'desc');
return $results->sort(
fn ($item) => $scores[$item->id()]['score'],
'desc'
);
},
/**
@@ -267,23 +280,8 @@ return [
* @param string|array $name Snippet name
* @param array $data Data array for the snippet
*/
'snippet' => function (App $kirby, $name, array $data = []): string {
$snippets = A::wrap($name);
foreach ($snippets as $name) {
$name = (string)$name;
$file = $kirby->root('snippets') . '/' . $name . '.php';
if (file_exists($file) === false) {
$file = $kirby->extensions('snippets')[$name] ?? null;
}
if ($file) {
break;
}
}
return Snippet::load($file, $data);
'snippet' => function (App $kirby, string|array $name, array $data = [], bool $slots = false): Snippet|string {
return Snippet::factory($name, $data, $slots);
},
/**
@@ -293,7 +291,7 @@ return [
* @param string $name Template name
* @param string $type Extension type
* @param string $defaultType Default extension type
* @return \Kirby\Cms\Template
* @return \Kirby\Template\Template
*/
'template' => function (App $kirby, string $name, string $type = 'html', string $defaultType = 'html') {
return new Template($name, $type, $defaultType);

View File

@@ -56,11 +56,14 @@ return [
}
return $api->upload(function ($source, $filename) use ($parent, $params, $map) {
$file = $parent->createFile([
$props = [
'source' => $source,
'template' => $params['template'] ?? null,
'filename' => $filename,
]);
];
// move the source file from the temp dir
$file = $parent->createFile($props, true);
if ($file instanceof File === false) {
throw new Exception('The file could not be uploaded');

View File

@@ -1,5 +1,7 @@
<?php
use Kirby\Field\FieldOptions;
return [
'extends' => 'radio',
'props' => [
@@ -20,5 +22,16 @@ return [
'placeholder' => function (string $placeholder = '—') {
return $placeholder;
},
],
'methods' => [
'getOptions' => function () {
$props = FieldOptions::polyfill($this->props);
// disable safe mode as the select field does not
// render HTML for the option text
$options = FieldOptions::factory($props['options'], false);
return $options->render($this->model());
}
]
];

View File

@@ -10,7 +10,7 @@ return [
* The field value will be converted with the selected converter before the value gets saved. Available converters: `lower`, `upper`, `ucfirst`, `slug`
*/
'converter' => function ($value = null) {
if ($value !== null && in_array($value, array_keys($this->converters())) === false) {
if ($value !== null && array_key_exists($value, $this->converters()) === false) {
throw new InvalidArgumentException([
'key' => 'field.converter.invalid',
'data' => ['converter' => $value]

View File

@@ -8,6 +8,8 @@ use Kirby\Cms\Url;
use Kirby\Filesystem\Asset;
use Kirby\Filesystem\F;
use Kirby\Http\Router;
use Kirby\Template\Slot;
use Kirby\Template\Snippet;
use Kirby\Toolkit\Date;
use Kirby\Toolkit\I18n;
use Kirby\Toolkit\Str;
@@ -131,6 +133,26 @@ if (Helpers::hasOverride('e') === false) { // @codeCoverageIgnore
}
}
if (Helpers::hasOverride('endslot') === false) { // @codeCoverageIgnore
/**
* Ends the last started template slot
*/
function endslot(): void
{
Slot::end();
}
}
if (Helpers::hasOverride('endsnippet') === false) { // @codeCoverageIgnore
/**
* Renders the currently active snippet with slots
*/
function endsnippet(): void
{
Snippet::end();
}
}
if (Helpers::hasOverride('esc') === false) { // @codeCoverageIgnore
/**
* Escape context specific output
@@ -538,6 +560,16 @@ if (Helpers::hasOverride('size') === false) { // @codeCoverageIgnore
}
}
if (Helpers::hasOverride('slot') === false) { // @codeCoverageIgnore
/**
* Starts a new template slot
*/
function slot(string $name = 'default'): void
{
Slot::begin($name);
}
}
if (Helpers::hasOverride('smartypants') === false) { // @codeCoverageIgnore
/**
* Enhances the given string with
@@ -555,15 +587,14 @@ if (Helpers::hasOverride('smartypants') === false) { // @codeCoverageIgnore
if (Helpers::hasOverride('snippet') === false) { // @codeCoverageIgnore
/**
* Embeds a snippet from the snippet folder
*
* @param string|array $name
* @param array|object $data
* @param bool $return
* @return string|null
*/
function snippet($name, $data = [], bool $return = false): string|null
{
return App::instance()->snippet($name, $data, $return);
function snippet(
$name,
$data = [],
bool $return = false,
bool $slots = false
): Snippet|string|null {
return App::instance()->snippet($name, $data, $return, $slots);
}
}

View File

@@ -326,7 +326,7 @@ return function (App $app) {
* Returns the number of words in the text
*/
'words' => function (Field $field) {
return str_word_count(strip_tags($field->value));
return str_word_count(strip_tags($field->value ?? ''));
},
// manipulators