Skip to content

Commit

Permalink
Merge pull request #5341 from getkirby/v4/release/alpha.4
Browse files Browse the repository at this point in the history
4.0.0-alpha.4
  • Loading branch information
bastianallgeier authored Jul 3, 2023
2 parents 509b81b + 449d791 commit 1206ff5
Show file tree
Hide file tree
Showing 181 changed files with 4,334 additions and 2,533 deletions.
2 changes: 1 addition & 1 deletion composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
"description": "The Kirby core",
"license": "proprietary",
"type": "kirby-cms",
"version": "4.0.0-alpha.3",
"version": "4.0.0-alpha.4",
"keywords": [
"kirby",
"cms",
Expand Down
2 changes: 1 addition & 1 deletion composer.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

33 changes: 19 additions & 14 deletions config/aliases.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@
return [
// cms classes
'collection' => 'Kirby\Cms\Collection',
'field' => 'Kirby\Cms\Field',
'file' => 'Kirby\Cms\File',
'files' => 'Kirby\Cms\Files',
'find' => 'Kirby\Cms\Find',
Expand All @@ -24,6 +23,9 @@
'users' => 'Kirby\Cms\Users',
'visitor' => 'Kirby\Cms\Visitor',

// content classes
'field' => 'Kirby\Content\Field',

// data handler
'data' => 'Kirby\Data\Data',
'json' => 'Kirby\Data\Json',
Expand Down Expand Up @@ -70,17 +72,20 @@
'xml' => 'Kirby\Toolkit\Xml',

// Deprecated aliases:
// Any of these might be removed at any point in the future
'kirby\cms\asset' => 'Kirby\Filesystem\Asset',
'kirby\cms\dir' => 'Kirby\Filesystem\Dir',
'kirby\cms\filename' => 'Kirby\Filesystem\Filename',
'kirby\cms\filefoundation' => 'Kirby\Filesystem\IsFile',
'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',
'kirby\toolkit\mime' => 'Kirby\Filesystem\Mime',
// Any of these might be removed at any point in the future
'kirby\cms\asset' => 'Kirby\Filesystem\Asset',
'kirby\cms\content' => 'Kirby\Content\Content',
'kirby\cms\contenttranslation' => 'Kirby\Content\ContentTranslation',
'kirby\cms\dir' => 'Kirby\Filesystem\Dir',
'kirby\cms\filename' => 'Kirby\Filesystem\Filename',
'kirby\cms\filefoundation' => 'Kirby\Filesystem\IsFile',
'kirby\cms\field' => 'Kirby\Content\Field',
'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',
'kirby\toolkit\mime' => 'Kirby\Filesystem\Mime',
];
35 changes: 35 additions & 0 deletions config/api/routes/kql.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
<?php

// @codeCoverageIgnoreStart
return [
'routes' => function ($kirby) {
return [
[
'pattern' => 'query',
'method' => 'POST|GET',
'auth' => $kirby->option('kql.auth') !== false,
'action' => function () use ($kirby) {
$kql = '\Kirby\Kql\Kql';

if (class_exists($kql) === false) {
return [
'code' => 500,
'status' => 'error',
'message' => 'KQL plugin is not installed',
];
}

$input = $kirby->request()->get();
$result = $kql::run($input);

return [
'code' => 200,
'result' => $result,
'status' => 'ok',
];
}
]
];
}
];
// @codeCoverageIgnoreEnd
41 changes: 24 additions & 17 deletions config/components.php
Original file line number Diff line number Diff line change
Expand Up @@ -136,7 +136,6 @@
/**
* Add your own search engine
*
* @param \Kirby\Cms\App $kirby Kirby instance
* @param \Kirby\Cms\Collection $collection Collection of searchable models
*/
'search' => function (
Expand All @@ -145,11 +144,6 @@
string $query = null,
string|array $params = []
): Collection {
// empty search query
if (empty(trim($query ?? '')) === true) {
return $collection->limit(0);
}

if (is_string($params) === true) {
$params = ['fields' => Str::split($params, '|')];
}
Expand All @@ -161,30 +155,42 @@
'words' => false,
];

$options = array_merge($defaults, $params);
$collection = clone $collection;
$options = array_merge($defaults, $params);
$query = trim($query);

// empty or too short search query
if (Str::length($query) < $options['minlength']) {
return $collection->limit(0);
}

$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) {
$words = array_diff($words, $options['stopwords']);
}

// returns an empty collection if there is no search word
if (empty($words) === true) {
return $collection->limit(0);
}

$words = A::map(
$words,
fn ($value) => $options['words'] ? '\b' . preg_quote($value) . '\b' : preg_quote($value)
fn ($value) => Str::wrap(preg_quote($value), $options['words'] ? '\b' : '')
);

// returns an empty collection if there is no search word
if (empty($words) === true) {
return $collection->limit(0);
$exact = preg_quote($query);

if ($options['words']) {
$exact = '(\b' . $exact . '\b)';
}

$query = Str::lower($query);
$preg = '!(' . implode('|', $words) . ')!i';
$scores = [];

$results = $collection->filter(function ($item) use ($query, $exact, $preg, $options, &$scores) {
$data = $item->content()->toArray();
$keys = array_keys($data);
Expand All @@ -196,10 +202,10 @@
$keys[] = 'role';
} elseif ($item instanceof Page) {
// apply the default score for pages
$options['score'] = array_merge([
'id' => 64,
'title' => 64,
], $options['score']);
$options['score'] = array_merge(
['id' => 64, 'title' => 64],
$options['score']
);
}

if (empty($options['fields']) === false) {
Expand Down Expand Up @@ -245,6 +251,7 @@
}

$scores[$item->id()] = $scoring;

return $scoring['hits'] > 0;
});

Expand Down
6 changes: 5 additions & 1 deletion config/fields/files.php
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
<?php

use Kirby\Cms\ModelWithContent;
use Kirby\Data\Data;
use Kirby\Toolkit\A;

Expand Down Expand Up @@ -36,7 +37,10 @@
'parentModel' => function () {
if (
is_string($this->parent) === true &&
$model = $this->model()->query($this->parent, 'Kirby\Cms\ModelWithContent')
$model = $this->model()->query(
$this->parent,
ModelWithContent::class
)
) {
return $model;
}
Expand Down
155 changes: 126 additions & 29 deletions config/fields/link.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,53 +7,150 @@

return [
'props' => [
'after' => null,
'before' => null,
'icon' => null,
'placeholder' => null,

/**
* @values 'anchor', 'url, 'page, 'file', 'email', 'tel', 'custom'
*/
'options' => function (array|null $options = null): array {
return $options ?? [
'url',
'page',
'file',
'email',
'tel',
'anchor',
'custom'
];
},
'value' => function (string|null $value = null) {
return $value ?? '';
}
],
'methods' => [
'activeTypes' => function () {
return array_filter($this->availableTypes(), function (string $type) {
return in_array($type, $this->props['options']) === true;
}, ARRAY_FILTER_USE_KEY);
},
'availableTypes' => function () {
return [
'anchor' => [
'detect' => function (string $value): bool {
return Str::startsWith($value, '#') === true;
},
'link' => function (string $value): string {
return $value;
},
'validate' => function (string $value): bool {
return Str::startsWith($value, '#') === true;
},
],
'email' => [
'detect' => function (string $value): bool {
return Str::startsWith($value, 'mailto:') === true;
},
'link' => function (string $value): string {
return str_replace('mailto:', '', $value);
},
'validate' => function (string $value): bool {
return V::email($value);
},
],
'file' => [
'detect' => function (string $value): bool {
return Str::startsWith($value, 'file://') === true;
},
'link' => function (string $value): string {
return $value;
},
'validate' => function (string $value): bool {
return V::uuid($value, 'file');
},
],
'page' => [
'detect' => function (string $value): bool {
return Str::startsWith($value, 'page://') === true;
},
'link' => function (string $value): string {
return $value;
},
'validate' => function (string $value): bool {
return V::uuid($value, 'page');
},
],
'tel' => [
'detect' => function (string $value): bool {
return Str::startsWith($value, 'tel:') === true;
},
'link' => function (string $value): string {
return str_replace('tel:', '', $value);
},
'validate' => function (string $value): bool {
return V::tel($value);
},
],
'url' => [
'detect' => function (string $value): bool {
return Str::startsWith($value, 'http://') === true || Str::startsWith($value, 'https://') === true;
},
'link' => function (string $value): string {
return $value;
},
'validate' => function (string $value): bool {
return V::url($value);
},
],

// needs to come last
'custom' => [
'detect' => function (string $value): bool {
return true;
},
'link' => function (string $value): string {
return $value;
},
'validate' => function (): bool {
return true;
},
]
];
},
],
'validations' => [
'value' => function ($value) {
if (V::uuid($value) === true) {
'value' => function (string|null $value) {
if (empty($value) === true) {
return true;
}

if (Str::startsWith($value, 'mailto:') === true) {
// get the plain email address
$email = str_replace('mailto:', '', $value);
$detected = false;

// validate the email address
if (V::email($email) === false) {
throw new InvalidArgumentException([
'key' => 'validation.email'
]);
foreach ($this->activeTypes() as $type => $options) {
if ($options['detect']($value) !== true) {
continue;
}

return true;
}
$link = $options['link']($value);
$detected = true;

if (Str::startsWith($value, 'tel:') === true) {
// get the plain phone number
$tel = str_replace('tel:', '', $value);

// validate the phone address
if (V::tel($tel) === false) {
if ($options['validate']($link) === false) {
throw new InvalidArgumentException([
'key' => 'validation.tel'
'key' => 'validation.' . $type
]);
}

return true;
}

if (Url::isAbsolute($value) === true) {
if (V::url($value) === false) {
throw new InvalidArgumentException([
'key' => 'validation.url'
]);
}

return true;
// none of the configured types has been detected
if ($detected === false) {
throw new InvalidArgumentException([
'key' => 'validation.linkType'
]);
}

return true;
},
]
];
Loading

0 comments on commit 1206ff5

Please sign in to comment.