Upgrade to 3.1.2

This commit is contained in:
Bastian Allgeier
2019-04-09 14:34:12 +02:00
parent 852a14595e
commit eb29ef6d6c
58 changed files with 535 additions and 258 deletions

View File

@@ -1,7 +1,7 @@
{
"name": "getkirby/cms",
"description": "The Kirby 3 core",
"version": "3.1.1",
"version": "3.1.2",
"license": "proprietary",
"keywords": ["kirby", "cms", "core"],
"homepage": "https://getkirby.com",
@@ -27,7 +27,7 @@
"mustangostang/spyc": "0.6.2",
"michelf/php-smartypants": "1.8.1",
"claviska/simpleimage": "3.3.3",
"phpmailer/phpmailer": "6.0.6",
"phpmailer/phpmailer": "6.0.7",
"filp/whoops": "2.3.1",
"true/punycode": "2.1.1",
"zendframework/zend-escaper": "2.6.0"

24
kirby/composer.lock generated
View File

@@ -4,7 +4,7 @@
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
"This file is @generated automatically"
],
"content-hash": "87a0387e02a6e94d8d89b88d8113176a",
"content-hash": "7c03372aae9d6bcfc8fdb6399a1e9e38",
"packages": [
{
"name": "claviska/simpleimage",
@@ -300,16 +300,16 @@
},
{
"name": "phpmailer/phpmailer",
"version": "v6.0.6",
"version": "v6.0.7",
"source": {
"type": "git",
"url": "https://github.com/PHPMailer/PHPMailer.git",
"reference": "8190d73eb5def11a43cfb020b7f36db65330698c"
"reference": "0c41a36d4508d470e376498c1c0c527aa36a2d59"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/PHPMailer/PHPMailer/zipball/8190d73eb5def11a43cfb020b7f36db65330698c",
"reference": "8190d73eb5def11a43cfb020b7f36db65330698c",
"url": "https://api.github.com/repos/PHPMailer/PHPMailer/zipball/0c41a36d4508d470e376498c1c0c527aa36a2d59",
"reference": "0c41a36d4508d470e376498c1c0c527aa36a2d59",
"shasum": ""
},
"require": {
@@ -362,7 +362,7 @@
}
],
"description": "PHPMailer is a full-featured email creation and transfer class for PHP",
"time": "2018-11-16T00:41:32+00:00"
"time": "2019-02-01T15:04:28+00:00"
},
{
"name": "psr/log",
@@ -413,16 +413,16 @@
},
{
"name": "symfony/polyfill-mbstring",
"version": "v1.10.0",
"version": "v1.11.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/polyfill-mbstring.git",
"reference": "c79c051f5b3a46be09205c73b80b346e4153e494"
"reference": "fe5e94c604826c35a32fa832f35bd036b6799609"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/c79c051f5b3a46be09205c73b80b346e4153e494",
"reference": "c79c051f5b3a46be09205c73b80b346e4153e494",
"url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/fe5e94c604826c35a32fa832f35bd036b6799609",
"reference": "fe5e94c604826c35a32fa832f35bd036b6799609",
"shasum": ""
},
"require": {
@@ -434,7 +434,7 @@
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "1.9-dev"
"dev-master": "1.11-dev"
}
},
"autoload": {
@@ -468,7 +468,7 @@
"portable",
"shim"
],
"time": "2018-09-21T13:07:52+00:00"
"time": "2019-02-06T07:57:58+00:00"
},
{
"name": "true/punycode",

View File

@@ -27,7 +27,7 @@ return [
return $page->errors();
},
'files' => function (Page $page) {
return $page->files();
return $page->files()->sortBy('sort', 'asc');
},
'hasChildren' => function (Page $page) {
return $page->hasChildren();

View File

@@ -20,8 +20,11 @@ return [
'content' => function (Site $site) {
return Form::for($site)->values();
},
'drafts' => function (Site $site) {
return $site->drafts();
},
'files' => function (Site $site) {
return $site->files();
return $site->files()->sortBy('sort', 'asc');
},
'options' => function (Site $site) {
return $site->permissions()->toArray();

View File

@@ -23,6 +23,9 @@ return [
'email' => function (User $user) {
return $user->email();
},
'files' => function (User $user) {
return $user->files()->sortBy('sort', 'asc');
},
'id' => function (User $user) {
return $user->id();
},

View File

@@ -29,7 +29,7 @@ return [
'pattern' => '(:all)/files',
'method' => 'GET',
'action' => function (string $path) {
return $this->parent($path)->files();
return $this->parent($path)->files()->sortBy('sort', 'asc');
}
],
[
@@ -62,7 +62,10 @@ return [
'pattern' => '(:all)/files/sort',
'method' => 'PATCH',
'action' => function (string $path) {
return $this->parent($path)->files()->changeSort($this->requestBody('files'));
return $this->parent($path)->files()->changeSort(
$this->requestBody('files'),
$this->requestBody('index')
);
}
],
[

View File

@@ -1,8 +1,10 @@
<?php
use Kirby\Cms\App;
use Kirby\Cms\File;
use Kirby\Cms\Filename;
use Kirby\Cms\FileVersion;
use Kirby\Cms\FileModifications;
use Kirby\Cms\Model;
use Kirby\Cms\Response;
use Kirby\Cms\Template;
@@ -15,6 +17,37 @@ use Kirby\Toolkit\F;
use Kirby\Toolkit\Tpl as Snippet;
return [
/**
* Used by the `css()` helper
*
* @param Kirby\Cms\App $kirby Kirby instance
* @param string $url Relative or absolute URL
* @param string|array $options An array of attributes for the link tag or a media attribute string
*/
'css' => function (App $kirby, string $url, $options = null): string {
return $url;
},
/**
* Modify URLs for file objects
*
* @param Kirby\Cms\App $kirby Kirby instance
* @param Kirby\Cms\File $file The original file object
* @return string
*/
'file::url' => function (App $kirby, File $file): string {
return $file->mediaUrl();
},
/**
* Adapt file characteristics
*
* @param Kirby\Cms\App $kirby Kirby instance
* @param Kirby\Cms\File|Kirby\Cms\FileModifications $file The file object
* @param array $options All thumb options (width, height, crop, blur, grayscale)
* @return Kirby\Cms\File|Kirby\Cms\FileVersion
*/
'file::version' => function (App $kirby, $file, array $options = []) {
if ($file->isResizable() === false) {
return $file;
@@ -48,9 +81,27 @@ return [
'url' => dirname($file->mediaUrl()) . '/' . $thumbName,
]);
},
'file::url' => function (App $kirby, $file) {
return $file->mediaUrl();
/**
* Used by the `js()` helper
*
* @param Kirby\Cms\App $kirby Kirby instance
* @param string $url Relative or absolute URL
* @param string|array $options An array of attributes for the link tag or a media attribute string
*/
'js' => function (App $kirby, string $url, $options = null): string {
return $url;
},
/**
* Add your own Markdown parser
*
* @param Kirby\Cms\App $kirby Kirby instance
* @param string $text Text to parse
* @param array $options Markdown options
* @param bool $inline Whether to wrap the text in `<p>` tags
* @return string
*/
'markdown' => function (App $kirby, string $text = null, array $options = [], bool $inline = false): string {
static $markdown;
@@ -58,6 +109,15 @@ return [
return $markdown->parse($text, $inline);
},
/**
* Add your own SmartyPants parser
*
* @param Kirby\Cms\App $kirby Kirby instance
* @param string $text Text to parse
* @param array $options SmartyPants options
* @return string
*/
'smartypants' => function (App $kirby, string $text = null, array $options = []): string {
static $smartypants;
@@ -65,7 +125,16 @@ return [
return $smartypants->parse($text);
},
'snippet' => function (App $kirby, string $name, array $data = []) {
/**
* Add your own snippet loader
*
* @param Kirby\Cms\App $kirby Kirby instance
* @param string $name Snippet name
* @param array $data Data array for the snippet
* @return string|null
*/
'snippet' => function (App $kirby, string $name, array $data = []): ?string {
$file = $kirby->root('snippets') . '/' . $name . '.php';
if (file_exists($file) === false) {
@@ -74,10 +143,30 @@ return [
return Snippet::load($file, $data);
},
/**
* Add your own template engine
*
* @param Kirby\Cms\App $kirby Kirby instance
* @param string $name Template name
* @param string $type Extension type
* @param string $defaultType Default extension type
* @return Kirby\Cms\Template
*/
'template' => function (App $kirby, string $name, string $type = 'html', string $defaultType = 'html') {
return new Template($name, $type, $defaultType);
},
'thumb' => function (App $kirby, string $src, string $dst, array $options) {
/**
* Add your own thumb generator
*
* @param Kirby\Cms\App $kirby Kirby instance
* @param string $src The root of the original file
* @param string $dst The root to the desired destination
* @param array $options All thumb options that should be applied: `width`, `height`, `crop`, `blur`, `grayscale`
* @return string
*/
'thumb' => function (App $kirby, string $src, string $dst, array $options): string {
$darkroom = Darkroom::factory(option('thumbs.driver', 'gd'), option('thumbs', []));
$options = $darkroom->preprocess($src, $options);
$root = (new Filename($src, $dst, $options))->toString();
@@ -87,4 +176,18 @@ return [
return $root;
},
/**
* Modify all URLs
*
* @param Kirby\Cms\App $kirby Kirby instance
* @param string $path URL path
* @param array|null $options Array of options for the Uri class
* @param Closure $originalHandler Callback function to the original URL handler with `$path` and `$options` as parameters
* @return string
*/
'url' => function (App $kirby, string $path = null, $options = [], Closure $originalHandler): string {
return $originalHandler($path, $options);
},
];

View File

@@ -4,7 +4,7 @@ use Kirby\Toolkit\A;
use Kirby\Toolkit\Str;
return [
'mixins' => ['options'],
'mixins' => ['min', 'options'],
'props' => [
/**
* Unset inherited props

View File

@@ -3,6 +3,7 @@
use Kirby\Toolkit\A;
return [
'mixins' => ['min'],
'props' => [
/**
* Unset inherited props

View File

@@ -0,0 +1,22 @@
<?php
return [
'computed' => [
'min' => function () {
// set min to at least 1, if required
if ($this->required === true) {
return $this->min ?? 1;
}
return $this->min;
},
'required' => function () {
// set required to true if min is set
if ($this->min) {
return true;
}
return $this->required;
}
]
];

View File

@@ -4,6 +4,7 @@ use Kirby\Toolkit\A;
use Kirby\Toolkit\I18n;
return [
'mixins' => ['min'],
'props' => [
/**
* Unset inherited props

View File

@@ -4,6 +4,7 @@ use Kirby\Cms\Form;
use Kirby\Cms\Blueprint;
return [
'mixins' => ['min'],
'props' => [
/**
* Unset inherited props
@@ -28,6 +29,14 @@ return [
'empty' => function ($empty = null) {
return I18n::translate($empty, $empty);
},
/**
* Set the default rows for the structure
*/
'default' => function (array $default = null) {
return $default;
},
/**
* Fields setup for the structure form. Works just like fields in regular forms.
*/
@@ -113,7 +122,7 @@ return [
}
return $columns;
},
}
],
'methods' => [
'rows' => function ($value) {
@@ -149,11 +158,11 @@ return [
]
];
},
'save' => function () {
'save' => function ($value) {
$data = [];
foreach ($this->value() as $row) {
$data[] = $this->form($row)->data();
foreach ($value as $row) {
$data[] = $this->form($row)->data(true);
}
return $data;

View File

@@ -1,7 +1,7 @@
<?php
return [
'mixins' => ['options'],
'mixins' => ['min', 'options'],
'props' => [
/**

View File

@@ -9,7 +9,7 @@ return [
'before' => null,
/**
* Enables/disables the format buttons. Can either be true/false or a list of allowed buttons. Available buttons: headlines, italic, bold, link, email, list, code, ul, ol
* Enables/disables the format buttons. Can either be true/false or a list of allowed buttons. Available buttons: headlines, italic, bold, link, email, file, list, code, ul, ol
*/
'buttons' => function ($buttons = true) {
return $buttons;

View File

@@ -1,6 +1,7 @@
<?php
return [
'mixins' => ['min'],
'props' => [
/**
* Unset inherited props

View File

@@ -105,16 +105,13 @@ function css($url, $options = null)
$kirby = App::instance();
if ($component = $kirby->component('css')) {
$url = $component($kirby, $url, $options);
}
if ($url === '@auto') {
if (!$url = Url::toTemplateAsset('css/templates', 'css')) {
return null;
}
}
$url = $kirby->component('css')($kirby, $url, $options);
$url = Url::to($url);
$attr = array_merge((array)$options, [
'href' => $url,
@@ -264,10 +261,20 @@ function image(string $path = null)
$uri = null;
}
$page = $uri === '/' ? site() : page($uri);
switch ($uri) {
case '/':
$parent = site();
break;
case null:
$parent = page();
break;
default:
$parent = page($uri);
break;
}
if ($page) {
return $page->image($filename);
if ($parent) {
return $parent->image($filename);
} else {
return null;
}
@@ -359,16 +366,13 @@ function js($url, $options = null)
$kirby = App::instance();
if ($component = $kirby->component('js')) {
$url = $component($kirby, $url, $options);
}
if ($url === '@auto') {
if (!$url = Url::toTemplateAsset('js/templates', 'js')) {
return null;
}
}
$url = $kirby->component('js')($kirby, $url, $options);
$url = Url::to($url);
$attr = array_merge((array)$options, ['src' => $url]);
@@ -711,12 +715,7 @@ function svg(string $file)
}
}
ob_start();
include $file;
$svg = ob_get_contents();
ob_end_clean();
return $svg;
return F::read($file);
}
/**

View File

@@ -5,7 +5,6 @@ use Kirby\Toolkit\I18n;
return [
'mixins' => [
'headline',
'help'
],
'props' => [
'text' => function ($text = null) {

View File

@@ -8,21 +8,5 @@ return [
'empty' => function ($empty = null) {
return I18n::translate($empty, $empty);
}
],
'methods' => [
'isFull' => function () {
if ($this->max) {
return $this->total >= $this->max;
}
return false;
},
'validateMax' => function () {
if ($this->max && $this->max < $this->total) {
return false;
}
return true;
}
]
];

View File

@@ -18,7 +18,7 @@ return [
return false;
},
'validateMax' => function () {
if ($this->max && $this->max < $this->total) {
if ($this->max && $this->total > $this->max) {
return false;
}

View File

@@ -188,7 +188,7 @@ return [
}
if ($this->validateMin() === false) {
$errors['min'] = I18n::template('error.section.pages.min.' . I18n::form($this->max), [
$errors['min'] = I18n::template('error.section.pages.min.' . I18n::form($this->min), [
'min' => $this->min,
'section' => $this->headline
]);
@@ -228,7 +228,7 @@ return [
return $this->pagination();
},
'sortable' => function () {
if ($this->status !== 'listed' && $this->status !== 'all') {
if (in_array($this->status, ['listed', 'published', 'all']) === false) {
return false;
}

View File

@@ -17,7 +17,7 @@ class Parsedown
{
# ~
const version = '1.8.0-beta-5';
const version = '1.8.0-beta-7';
# ~
@@ -431,7 +431,21 @@ class Parsedown
);
if ($infostring !== '') {
$Element['attributes'] = array('class' => "language-$infostring");
/**
* https://www.w3.org/TR/2011/WD-html5-20110525/elements.html#classes
* Every HTML element may have a class attribute specified.
* The attribute, if specified, must have a value that is a set
* of space-separated tokens representing the various classes
* that the element belongs to.
* [...]
* The space characters, for the purposes of this specification,
* are U+0020 SPACE, U+0009 CHARACTER TABULATION (tab),
* U+000A LINE FEED (LF), U+000C FORM FEED (FF), and
* U+000D CARRIAGE RETURN (CR).
*/
$language = substr($infostring, 0, strcspn($infostring, " \t\n\f\r"));
$Element['attributes'] = array('class' => "language-$language");
}
$Block = array(

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@@ -160,6 +160,10 @@ class App
*/
public function api(): Api
{
if ($this->api !== null) {
return $this->api;
}
$root = static::$root . '/config/api';
$extensions = $this->extensions['api'] ?? [];
$routes = (include $root . '/routes.php')($this);
@@ -174,7 +178,7 @@ class App
'kirby' => $this,
];
return $this->api = $this->api ?? new Api($api);
return $this->api = new Api($api);
}
/**
@@ -254,7 +258,7 @@ class App
* automatically injected
*
* @param string $name
* @return void
* @return Kirby\Cms\Collection|null
*/
public function collection(string $name)
{
@@ -682,7 +686,7 @@ class App
*/
public function markdown(string $text = null, bool $inline = false): string
{
return $this->extensions['components']['markdown']($this, $text, $this->options['markdown'] ?? [], $inline);
return $this->component('markdown')($this, $text, $this->options['markdown'] ?? [], $inline);
}
/**
@@ -1091,7 +1095,7 @@ class App
*/
public function smartypants(string $text = null): string
{
return $this->extensions['components']['smartypants']($this, $text, $this->options['smartypants'] ?? []);
return $this->component('smartypants')($this, $text, $this->options['smartypants'] ?? []);
}
/**
@@ -1103,7 +1107,7 @@ class App
*/
public function snippet(string $name, array $data = []): ?string
{
return $this->extensions['components']['snippet']($this, $name, array_merge($this->data, $data));
return $this->component('snippet')($this, $name, array_merge($this->data, $data));
}
/**
@@ -1125,7 +1129,7 @@ class App
*/
public function template(string $name, string $type = 'html', string $defaultType = 'html'): Template
{
return $this->extensions['components']['template']($this, $name, $type, $defaultType);
return $this->component('template')($this, $name, $type, $defaultType);
}
/**
@@ -1134,11 +1138,11 @@ class App
* @param string $src
* @param string $dst
* @param array $options
* @return null
* @return string
*/
public function thumb(string $src, string $dst, array $options = [])
public function thumb(string $src, string $dst, array $options = []): string
{
return $this->extensions['components']['thumb']($this, $src, $dst, $options);
return $this->component('thumb')($this, $src, $dst, $options);
}
/**

View File

@@ -86,6 +86,10 @@ trait AppPlugins
protected function extendApi($api): array
{
if (is_array($api) === true) {
if (is_a($api['routes'] ?? [], Closure::class) === true) {
$api['routes'] = $api['routes']($this);
}
return $this->extensions['api'] = A::merge($this->extensions['api'], $api, A::MERGE_APPEND);
} else {
return $this->extensions['api'];
@@ -363,6 +367,7 @@ trait AppPlugins
protected function extensionsFromSystem()
{
// Form Field Mixins
FormField::$mixins['min'] = include static::$root . '/config/fields/mixins/min.php';
FormField::$mixins['options'] = include static::$root . '/config/fields/mixins/options.php';
// Tag Aliases

View File

@@ -79,6 +79,48 @@ class Content
return $this->toArray();
}
/**
* Converts the content to a new blueprint
*
* @param string $to
* @return array
*/
public function convertTo(string $to): array
{
// prepare data
$data = [];
$content = $this;
// blueprints
$old = $this->parent->blueprint();
$subfolder = dirname($old->name());
$new = Blueprint::factory($subfolder . '/' . $to, $subfolder . '/default', $this->parent);
// forms
$oldForm = new Form(['fields' => $old->fields(), 'model' => $this->parent]);
$newForm = new Form(['fields' => $new->fields(), 'model' => $this->parent]);
// fields
$oldFields = $oldForm->fields();
$newFields = $newForm->fields();
// go through all fields of new template
foreach ($newFields as $newField) {
$name = $newField->name();
$oldField = $oldFields->get($name);
// field name and type matches with old template
if ($oldField && $oldField->type() === $newField->type()) {
$data[$name] = $content->get($name)->value();
} else {
$data[$name] = $newField->default();
}
}
// preserve existing fields
return array_merge($this->data, $data);
}
/**
* Returns the raw data array
*

View File

@@ -75,12 +75,16 @@ class Email
$html = $this->getTemplate($this->props['template'], 'html');
$text = $this->getTemplate($this->props['template'], 'text');
if ($html->exists() && $text->exists()) {
if ($html->exists()) {
$this->props['body'] = [
'html' => $html->render($data),
'text' => $text->render($data),
'html' => $html->render($data)
];
// fallback to single email text template
if ($text->exists()) {
$this->props['body']['text'] = $text->render($data);
}
// fallback to single email text template
} elseif ($text->exists()) {
$this->props['body'] = $text->render($data);
} else {

View File

@@ -367,6 +367,28 @@ class File extends ModelWithContent
return $this->parent();
}
/**
* Get the file's last modification time.
*
* @param string $format
* @param string|null $handler date or strftime
* @return mixed
*/
public function modified(string $format = null, string $handler = null)
{
$file = F::modified($this->root());
$content = F::modified($this->contentFile());
$modified = max($file, $content);
if (is_null($format) === true) {
return $modified;
}
$handler = $handler ?? $this->kirby()->option('date.handler', 'date');
return $handler($format, $modified);
}
/**
* Returns the parent Page object
*
@@ -418,14 +440,12 @@ class File extends ModelWithContent
$definition = array_merge($types[$this->type()] ?? [], $extensions[$this->extension()] ?? []);
$settings = [
return [
'type' => $definition['type'] ?? 'file',
'back' => 'pattern',
'color' => $definition['color'] ?? $colorWhite,
'back' => $params['back'] ?? 'pattern',
'ratio' => $params['ratio'] ?? null,
];
return $settings;
}
/**
@@ -745,6 +765,6 @@ class File extends ModelWithContent
*/
public function url(): string
{
return $this->url ?? $this->url = $this->kirby()->component('file::url')($this->kirby(), $this, []);
return $this->url ?? $this->url = $this->kirby()->component('file::url')($this->kirby(), $this);
}
}

View File

@@ -205,8 +205,7 @@ trait FileActions
}
/**
* Alias for changeName
* @deprecated
* @deprecated 3.0.0 Use `File::changeName()` instead
*
* @param string $name
* @param bool $sanitize

View File

@@ -55,17 +55,16 @@ class Files extends Collection
* Sort all given files by the
* order in the array
*
* @param array $files
* @param array $files List of filenames
* @param int $offset Sorting offset
* @return self
*/
public function changeSort(array $files)
public function changeSort(array $files, int $offset = 0)
{
$index = 0;
foreach ($files as $filename) {
if ($file = $this->get($filename)) {
$index++;
$file->changeSort($index);
$offset++;
$file->changeSort($offset);
}
}

View File

@@ -2,6 +2,7 @@
namespace Kirby\Cms;
use Kirby\Data\Data;
use Kirby\Exception\DuplicateException;
use Kirby\Exception\Exception;
use Kirby\Exception\InvalidArgumentException;
@@ -9,6 +10,7 @@ use Kirby\Exception\LogicException;
use Kirby\Exception\PermissionException;
use Kirby\Toolkit\F;
use Kirby\Toolkit\Str;
use Throwable;
/**
* The `$language` object represents
@@ -318,7 +320,11 @@ class Language extends Model
*/
public function pattern(): string
{
return $this->url;
if (empty($this->url) === true) {
return $this->code;
}
return trim($this->url, '/');
}
/**
@@ -339,13 +345,27 @@ class Language extends Model
*/
public function save(): self
{
$data = $this->toArray();
try {
$existingData = Data::read($this->root());
} catch (Throwable $e) {
$existingData = [];
}
unset($data['url']);
$props = [
'code' => $this->code(),
'default' => $this->isDefault(),
'direction' => $this->direction(),
'locale' => $this->locale(),
'name' => $this->name(),
'translations' => $this->translations(),
'url' => $this->url,
];
$export = '<?php' . PHP_EOL . PHP_EOL . 'return ' . var_export($data, true) . ';';
$data = array_merge($existingData, $props);
F::write($this->root(), $export);
ksort($data);
Data::write($this->root(), $data);
return $this;
}
@@ -416,7 +436,7 @@ class Language extends Model
*/
protected function setUrl(string $url = null): self
{
$this->url = $url !== null ? trim($url, '/') : $this->code;
$this->url = $url;
return $this;
}
@@ -455,7 +475,7 @@ class Language extends Model
*/
public function url(): string
{
return Url::to($this->url);
return Url::to($this->pattern());
}
/**

View File

@@ -6,6 +6,7 @@ use Closure;
use Kirby\Data\Data;
use Kirby\Exception\Exception;
use Kirby\Exception\NotFoundException;
use Kirby\Http\Uri;
use Kirby\Toolkit\A;
use Kirby\Toolkit\F;
use Kirby\Toolkit\Str;
@@ -579,8 +580,18 @@ class Page extends ModelWithContent
// inspect the current request
$request = $kirby->request();
// disable the pages cache for any request types but GET or HEAD or special data
if (in_array($request->method(), ['GET', 'HEAD']) === false || empty($request->data()) === false) {
// disable the pages cache for any request types but GET or HEAD
if (in_array($request->method(), ['GET', 'HEAD']) === false) {
return false;
}
// disable the pages cache when there's request data
if (empty($request->data()) === false) {
return false;
}
// disable the pages cache when there are any params
if ($request->params()->isNotEmpty()) {
return false;
}
@@ -875,30 +886,21 @@ class Page extends ModelWithContent
*/
public function panelIcon(array $params = null): array
{
$options = [
'type' => 'page',
'ratio' => $params['ratio'] ?? null,
'back' => $params['back'] ?? 'black',
];
if ($icon = $this->blueprint()->icon()) {
$options['type'] = $icon;
// check for emojis
if (strlen($icon) !== Str::length($icon)) {
$options = [
'type' => $icon,
'back' => 'black',
'emoji' => true
];
} else {
$options = [
'type' => $icon,
'back' => 'black',
];
$options['emoji'] = true;
}
} else {
$options = [
'type' => 'page',
'back' => 'black',
];
}
$options['ratio'] = $params['ratio'] ?? null;
return $options;
}
@@ -1062,7 +1064,10 @@ class Page extends ModelWithContent
}
if ($this->isDraft() === true) {
$url .= '?token=' . $this->token();
$uri = new Uri($url);
$uri->query->token = $this->token();
$url = $uri->toString();
}
return $url;

View File

@@ -29,6 +29,11 @@ trait PageActions
throw new LogicException('Drafts cannot change their sorting number');
}
// don't run the action if everything stayed the same
if ($this->num() === $num) {
return $this;
}
return $this->commit('changeNum', [$this, $num], function ($oldPage, $num) {
$newPage = $oldPage->clone([
'num' => $num,
@@ -213,24 +218,19 @@ trait PageActions
return $this;
}
// prepare data to transfer between blueprints
$oldBlueprint = 'pages/' . $this->template();
$newBlueprint = 'pages/' . $template;
return $this->commit('changeTemplate', [$this, $template], function ($oldPage, $template) use ($oldBlueprint, $newBlueprint) {
return $this->commit('changeTemplate', [$this, $template], function ($oldPage, $template) {
if ($this->kirby()->multilang() === true) {
$newPage = $this->clone([
'template' => $template
]);
foreach ($this->kirby()->languages()->codes() as $code) {
$content = $oldPage->content($code)->convertTo($template);
if (F::remove($oldPage->contentFile($code)) !== true) {
throw new LogicException('The old text file could not be removed');
}
// convert the content to the new blueprint
$content = $oldPage->transferData($oldPage->content($code), $oldBlueprint, $newBlueprint)['data'];
// save the language file
$newPage->save($content, $code);
}
@@ -239,7 +239,7 @@ trait PageActions
return $newPage->clone();
} else {
$newPage = $this->clone([
'content' => $this->transferData($this->content(), $oldBlueprint, $newBlueprint)['data'],
'content' => $this->content()->convertTo($template),
'template' => $template
]);
@@ -596,79 +596,6 @@ trait PageActions
return $this->changeStatus('listed', $position);
}
/**
* Transfers data from old to new blueprint and tracks changes
*
* @param Content $content
* @param string $old Old blueprint
* @param string $new New blueprint
* @return array
*/
protected function transferData(Content $content, string $old, string $new): array
{
// Prepare data
$data = [];
$old = Blueprint::factory($old, 'pages/default', $this);
$new = Blueprint::factory($new, 'pages/default', $this);
$oldForm = new Form(['fields' => $old->fields(), 'model' => $this]);
$newForm = new Form(['fields' => $new->fields(), 'model' => $this]);
$oldFields = $oldForm->fields();
$newFields = $newForm->fields();
// Tracking changes
$added = [];
$replaced = [];
$removed = [];
// Ensure to keep title
$data['title'] = $content->get('title')->value();
// Go through all fields of new template
foreach ($newFields as $newField) {
$name = $newField->name();
$oldField = $oldFields->get($name);
// Field name matches with old template
if ($oldField !== null) {
// Same field type, add and keep value
if ($oldField->type() === $newField->type()) {
$data[$name] = $content->get($name)->value();
// Different field type, add with empty value
} else {
$data[$name] = null;
$replaced[$name] = $oldFields->get($name)->label() ?? $name;
}
// Field does not exist in old template,
// add with empty or preserved value
} else {
$preserved = $content->get($name);
$data[$name] = $preserved ? $preserved->value(): null;
$added[$name] = $newField->label() ?? $name;
}
}
// Go through all values to preserve them
foreach ($content->fields() as $field) {
$name = $field->key();
$newField = $newFields->get($name);
if ($newField === null) {
$data[$name] = $field->value();
$removed[$name] = $field->name();
}
}
return [
'data' => $data,
'added' => $added,
'replaced' => $replaced,
'removed' => $removed
];
}
/**
* Convert a page from listed or
* unlisted to draft.

View File

@@ -26,7 +26,7 @@ trait PageSiblings
}
/**
* @deprecated Use `Page::hasNextListed` instead
* @deprecated 3.0.0 Use `Page::hasNextListed` instead
* @return boolean
*/
public function hasNextVisible(): bool
@@ -46,7 +46,7 @@ trait PageSiblings
}
/**
* @deprecated Use `Page::hasPrevUnlisted` instead
* @deprecated 3.0.0 Use `Page::hasPrevUnlisted` instead
* @return boolean
*/
public function hasPrevInvisible(): bool
@@ -77,7 +77,7 @@ trait PageSiblings
}
/**
* @deprecated Use `Page::hasPrevListed instead`
* @deprecated 3.0.0 Use `Page::hasPrevListed instead`
* @return boolean
*/
public function hasPrevVisible(): bool
@@ -86,7 +86,7 @@ trait PageSiblings
}
/**
* @deprecated Use `Page::nextUnlisted()` instead
* @deprecated 3.0.0 Use `Page::nextUnlisted()` instead
* @return self|null
*/
public function nextInvisible()
@@ -115,7 +115,7 @@ trait PageSiblings
}
/**
* @deprecated Use `Page::prevListed()` instead
* @deprecated 3.0.0 Use `Page::prevListed()` instead
* @return self|null
*/
public function nextVisible()
@@ -124,7 +124,7 @@ trait PageSiblings
}
/**
* @deprecated Use `Page::prevUnlisted()` instead
* @deprecated 3.0.0 Use `Page::prevUnlisted()` instead
* @return self|null
*/
public function prevInvisible()
@@ -153,7 +153,7 @@ trait PageSiblings
}
/**
* @deprecated Use `Page::prevListed()` instead
* @deprecated 3.0.0 Use `Page::prevListed()` instead
* @return self|null
*/
public function prevVisible()

View File

@@ -69,7 +69,8 @@ class Search
}
if (empty($options['fields']) === false) {
$keys = array_intersect($keys, $options['fields']);
$fields = array_map('strtolower', $options['fields']);
$keys = array_intersect($keys, $fields);
}
$item->searchHits = 0;

View File

@@ -80,12 +80,8 @@ class Url extends BaseUrl
$path = $page->url($language);
}
if ($handler = $kirby->component('url')) {
return $handler($kirby, $path, $options, function (string $path = null, $options = null) {
return parent::to($path, $options);
});
}
return parent::to($path, $options);
return $kirby->component('url')($kirby, $path, $options, function (string $path = null, $options = null) {
return parent::to($path, $options);
});
}
}

View File

@@ -292,11 +292,15 @@ class User extends ModelWithContent
/**
* Compares the current object with the given user object
*
* @param User $user
* @param User|null $user
* @return bool
*/
public function is(User $user): bool
public function is(User $user = null): bool
{
if ($user === null) {
return false;
}
return $this->id() === $user->id();
}

View File

@@ -185,8 +185,15 @@ trait UserActions
$user->writePassword($user->password());
// always create users in the default language
if ($user->kirby()->multilang() === true) {
$languageCode = $user->kirby()->defaultLanguage()->code();
} else {
$languageCode = null;
}
// write the user data
return $user->save();
return $user->save($user->content()->toArray(), $languageCode);
});
}

View File

@@ -78,7 +78,7 @@ class Users extends Collection
public function findByKey($key)
{
if (Str::contains($key, '@') === true) {
return parent::findBy('email', $key);
return parent::findBy('email', strtolower($key));
}
return parent::findByKey($key);

View File

@@ -30,9 +30,9 @@ class Data
* @var array
*/
public static $aliases = [
'yml' => 'yaml',
'md' => 'txt',
'mdown' => 'txt'
'mdown' => 'txt',
'yml' => 'yaml',
];
/**
@@ -42,8 +42,9 @@ class Data
*/
public static $handlers = [
'json' => 'Kirby\Data\Json',
'php' => 'Kirby\Data\PHP',
'txt' => 'Kirby\Data\Txt',
'yaml' => 'Kirby\Data\Yaml',
'txt' => 'Kirby\Data\Txt'
];
/**

View File

@@ -32,10 +32,10 @@ abstract class Handler
/**
* Converts an array to an encoded string
*
* @param array $data
* @param mixed $data
* @return string
*/
abstract public static function encode(array $data): string;
abstract public static function encode($data): string;
/**
* Reads data from a file

View File

@@ -18,10 +18,10 @@ class Json extends Handler
/**
* Converts an array to an encoded JSON string
*
* @param array $data
* @param mixed $data
* @return string
*/
public static function encode(array $data): string
public static function encode($data): string
{
return json_encode($data);
}

87
kirby/src/Data/PHP.php Executable file
View File

@@ -0,0 +1,87 @@
<?php
namespace Kirby\Data;
use Exception;
use Kirby\Toolkit\F;
/**
* Reader and write of PHP files with data in a returned array
*
* @package Kirby Data
* @author Bastian Allgeier <bastian@getkirby.com>
* @link http://getkirby.com
* @copyright Bastian Allgeier
* @license MIT
*/
class PHP extends Handler
{
/**
* Converts an array to PHP file content
*
* @param mixed $data
* @param string $indent
* @return string
*/
public static function encode($data, $indent = ''): string
{
switch (gettype($data)) {
case 'array':
$indexed = array_keys($data) === range(0, count($data) - 1);
$array = [];
foreach ($data as $key => $value) {
$array[] = "$indent " . ($indexed ? '' : static::encode($key) . ' => ') . static::encode($value, "$indent ");
}
return "[\n" . implode(",\n", $array) . "\n" . $indent . "]";
case 'boolean':
return $data ? 'true' : 'false';
case 'int':
case 'double':
return $data;
default:
return var_export($data, true);
}
}
/**
* PHP arrays don't have to be decoded
*
* @param array $array
* @return array
*/
public static function decode($array): array
{
return $array;
}
/**
* Reads data from a file
*
* @param string $file
* @return array
*/
public static function read(string $file): array
{
if (file_exists($file) !== true) {
throw new Exception('The file "' . $file . '" does not exist');
}
return (array)(include $file);
}
/**
* Creates a PHP file with the given data
*
* @param array $data
* @return boolean
*/
public static function write(string $file = null, array $data = []): bool
{
$php = static::encode($data);
$php = "<?php\n\nreturn $php;";
return F::write($file, $php);
}
}

View File

@@ -19,14 +19,14 @@ class Txt extends Handler
/**
* Converts an array to an encoded Kirby txt string
*
* @param array $data
* @param mixed $data
* @return string
*/
public static function encode(array $data): string
public static function encode($data): string
{
$result = [];
foreach ($data as $key => $value) {
foreach ((array)$data as $key => $value) {
if (empty($key) === true || $value === null) {
continue;
}

View File

@@ -20,10 +20,10 @@ class Yaml extends Handler
/**
* Converts an array to an encoded YAML string
*
* @param array $data
* @param mixed $data
* @return string
*/
public static function encode(array $data): string
public static function encode($data): string
{
// fetch the current locale setting for numbers
$locale = setlocale(LC_NUMERIC, 0);

View File

@@ -32,7 +32,7 @@ class Body
return $this->html;
}
public function text(): string
public function text()
{
return $this->text;
}
@@ -43,7 +43,7 @@ class Body
return $this;
}
protected function setText(string $text)
protected function setText(string $text = null)
{
$this->text = $text;
return $this;

View File

@@ -102,12 +102,6 @@ class Field extends Component
'before' => function ($before = null) {
return I18n::translate($before, $before);
},
/**
* Conditions when the field will be shown
*/
'when' => function ($when = null) {
return $when;
},
/**
* Default value for the field, which will be used when a Page/File/User is created
*/
@@ -156,6 +150,12 @@ class Field extends Component
'translate' => function (bool $translate = true): bool {
return $translate;
},
/**
* Conditions when the field will be shown
*/
'when' => function ($when = null) {
return $when;
},
/**
* The width of the field in the field grid. Available widths: 1/1, 1/2, 1/3, 1/4, 2/3, 3/4
*/

View File

@@ -15,7 +15,7 @@ use Kirby\Toolkit\Obj;
/**
* Foundation for the Options query
* classes, that are used to generate
* options arrays for select fiels,
* options arrays for select fields,
* radio boxes, checkboxes and more.
*/
class Options
@@ -121,7 +121,9 @@ class Options
}
// translate the option text
$option['text'] = I18n::translate($option['text'], $option['text']);
if (is_array($option['text']) === true) {
$option['text'] = I18n::translate($option['text'], $option['text']);
}
// add the option to the list
$result[] = $option;

View File

@@ -65,7 +65,7 @@ class OptionsQuery
}
$data = $this->data();
$query = new Query($this->query(), $this->data());
$query = new Query($this->query(), $data);
$result = $query->result();
$result = $this->resultToCollection($result);
$options = [];

View File

@@ -349,6 +349,9 @@ class Collection extends Iterator implements Countable
foreach ($keys as $key) {
if ($item = $this->findByKey($key)) {
if (is_object($item) && method_exists($item, 'id') === true) {
$key = $item->id();
}
$result[$key] = $item;
}
}

View File

@@ -71,6 +71,11 @@ class V
$value = $params[$index] ?? null;
if (is_array($value) === true) {
foreach ($value as $index => $item) {
if (is_array($item) === true) {
$value[$index] = implode('|', $item);
}
}
$value = implode(', ', $value);
}

View File

@@ -105,6 +105,7 @@ return array(
'Kirby\\Data\\Data' => $baseDir . '/src/Data/Data.php',
'Kirby\\Data\\Handler' => $baseDir . '/src/Data/Handler.php',
'Kirby\\Data\\Json' => $baseDir . '/src/Data/Json.php',
'Kirby\\Data\\PHP' => $baseDir . '/src/Data/PHP.php',
'Kirby\\Data\\Txt' => $baseDir . '/src/Data/Txt.php',
'Kirby\\Data\\Yaml' => $baseDir . '/src/Data/Yaml.php',
'Kirby\\Database\\Database' => $baseDir . '/src/Database/Database.php',

View File

@@ -195,6 +195,7 @@ class ComposerStaticInit12091bebabd81c9aba88b2aeec22c8d7
'Kirby\\Data\\Data' => __DIR__ . '/../..' . '/src/Data/Data.php',
'Kirby\\Data\\Handler' => __DIR__ . '/../..' . '/src/Data/Handler.php',
'Kirby\\Data\\Json' => __DIR__ . '/../..' . '/src/Data/Json.php',
'Kirby\\Data\\PHP' => __DIR__ . '/../..' . '/src/Data/PHP.php',
'Kirby\\Data\\Txt' => __DIR__ . '/../..' . '/src/Data/Txt.php',
'Kirby\\Data\\Yaml' => __DIR__ . '/../..' . '/src/Data/Yaml.php',
'Kirby\\Database\\Database' => __DIR__ . '/../..' . '/src/Database/Database.php',

View File

@@ -23,4 +23,4 @@ $PHPMAILER_LANG['signing'] = 'Ralat pada tanda tangan: ';
$PHPMAILER_LANG['smtp_connect_failed'] = 'SMTP Connect() telah gagal.';
$PHPMAILER_LANG['smtp_error'] = 'Ralat pada pelayan SMTP: ';
$PHPMAILER_LANG['variable_set'] = 'Tidak boleh menetapkan atau menetapkan semula pembolehubah: ';
//$PHPMAILER_LANG['extension_missing'] = 'Extension missing: ';
$PHPMAILER_LANG['extension_missing'] = 'Sambungan hilang: ';

View File

@@ -701,7 +701,7 @@ class PHPMailer
*
* @var string
*/
const VERSION = '6.0.6';
const VERSION = '6.0.7';
/**
* Error severity: message only, continue processing.

View File

@@ -45,7 +45,7 @@ class POP3
*
* @var string
*/
const VERSION = '6.0.6';
const VERSION = '6.0.7';
/**
* Default POP3 port number.

View File

@@ -34,7 +34,7 @@ class SMTP
*
* @var string
*/
const VERSION = '6.0.6';
const VERSION = '6.0.7';
/**
* SMTP line break constant.