Upgrade to 3.5.1

This commit is contained in:
Bastian Allgeier
2021-01-19 12:20:38 +01:00
parent 8f55019e01
commit 99c36fa137
119 changed files with 2973 additions and 3707 deletions

View File

@@ -41,8 +41,11 @@ class Api extends BaseApi
$allowImpersonation = $this->kirby()->option('api.allowImpersonation', false);
if ($user = $this->kirby->user(null, $allowImpersonation)) {
$this->kirby->setCurrentTranslation($user->language());
$translation = $user->language();
} else {
$translation = $this->kirby->panelLanguage();
}
$this->kirby->setCurrentTranslation($translation);
return parent::call($path, $method, $requestData);
}

View File

@@ -852,7 +852,7 @@ class App
*/
public function markdown(string $text = null, bool $inline = false): string
{
return $this->component('markdown')($this, $text, $this->options['markdown'] ?? [], $inline);
return ($this->component('markdown'))($this, $text, $this->options['markdown'] ?? [], $inline);
}
/**
@@ -1101,6 +1101,7 @@ class App
if ($page) {
try {
$response = $this->response();
$output = $page->render([], $extension);
// attach a MIME type based on the representation
// only if no custom MIME type was set
@@ -1108,7 +1109,7 @@ class App
$response->type($extension);
}
return $response->body($page->render([], $extension));
return $response->body($output);
} catch (NotFoundException $e) {
return null;
}
@@ -1373,7 +1374,7 @@ class App
}
}
return $this->component('smartypants')($this, $text, $options);
return ($this->component('smartypants'))($this, $text, $options);
}
/**
@@ -1387,7 +1388,7 @@ class App
*/
public function snippet($name, array $data = []): ?string
{
return $this->component('snippet')($this, $name, array_merge($this->data, $data));
return ($this->component('snippet'))($this, $name, array_merge($this->data, $data));
}
/**
@@ -1412,7 +1413,7 @@ class App
*/
public function template(string $name, string $type = 'html', string $defaultType = 'html')
{
return $this->component('template')($this, $name, $type, $defaultType);
return ($this->component('template'))($this, $name, $type, $defaultType);
}
/**
@@ -1425,7 +1426,7 @@ class App
*/
public function thumb(string $src, string $dst, array $options = []): string
{
return $this->component('thumb')($this, $src, $dst, $options);
return ($this->component('thumb'))($this, $src, $dst, $options);
}
/**

View File

@@ -2,7 +2,6 @@
namespace Kirby\Cms;
use Kirby\Cache\Cache;
use Kirby\Cache\NullCache;
use Kirby\Exception\InvalidArgumentException;
@@ -73,7 +72,7 @@ trait AppCaches
*/
protected function cacheOptions(string $key): array
{
$options = $this->option($cacheKey = $this->cacheOptionsKey($key), false);
$options = $this->option($this->cacheOptionsKey($key), false);
if ($options === false) {
return [

View File

@@ -2,7 +2,6 @@
namespace Kirby\Cms;
use Kirby\Data\Data;
use Kirby\Toolkit\I18n;
use Kirby\Toolkit\Locale;
use Kirby\Toolkit\Str;
@@ -46,6 +45,7 @@ trait AppTranslations
return $data;
};
// the actual locale is set using $app->setCurrentTranslation()
I18n::$locale = function (): string {
if ($this->multilang() === true) {
return $this->defaultLanguage()->code();
@@ -54,11 +54,25 @@ trait AppTranslations
}
};
I18n::$fallback = function (): string {
I18n::$fallback = function (): array {
if ($this->multilang() === true) {
return $this->defaultLanguage()->code();
// first try to fall back to the configured default language
$defaultCode = $this->defaultLanguage()->code();
$fallback = [$defaultCode];
// if the default language is specified with a country code
// (e.g. `en-us`), also try with just the language code
if (preg_match('/^([a-z]{2})-[a-z]+$/i', $defaultCode, $matches) === 1) {
$fallback[] = $matches[1];
}
// fall back to the complete English translation
// as a last resort
$fallback[] = 'en';
return $fallback;
} else {
return 'en';
return ['en'];
}
};
@@ -74,6 +88,30 @@ trait AppTranslations
}
}
/**
* Returns the language code that will be used
* for the Panel if no user is logged in or if
* no language is configured for the user
*
* @return string
*/
public function panelLanguage(): string
{
if ($this->multilang() === true) {
$defaultCode = $this->defaultLanguage()->code();
// extract the language code from a language that
// contains the country code (e.g. `en-us`)
if (preg_match('/^([a-z]{2})-[a-z]+$/i', $defaultCode, $matches) === 1) {
$defaultCode = $matches[1];
}
} else {
$defaultCode = 'en';
}
return $this->option('panel.language', $defaultCode);
}
/**
* Load and set the current language if it exists
* Otherwise fall back to the default language
@@ -132,10 +170,10 @@ trait AppTranslations
/**
* Load a specific translation by locale
*
* @param string|null $locale
* @param string|null $locale Locale name or `null` for the current locale
* @return \Kirby\Cms\Translation|null
*/
public function translation(string $locale = null)
public function translation(?string $locale = null)
{
$locale = $locale ?? I18n::locale();
$locale = basename($locale);

View File

@@ -2,6 +2,7 @@
namespace Kirby\Cms;
use Kirby\Cms\Auth\Status;
use Kirby\Data\Data;
use Kirby\Exception\InvalidArgumentException;
use Kirby\Exception\LogicException;
@@ -32,9 +33,41 @@ class Auth
*/
public static $challenges = [];
/**
* Currently impersonated user
*
* @var \Kirby\Cms\User|null
*/
protected $impersonate;
/**
* Kirby instance
*
* @var \Kirby\Cms\App
*/
protected $kirby;
/**
* Cache of the auth status object
*
* @var \Kirby\Cms\Auth\Status
*/
protected $status;
/**
* Instance of the currently logged in user or
* `false` if the user was not yet determined
*
* @var \Kirby\Cms\User|null|false
*/
protected $user = false;
/**
* Exception that was thrown while
* determining the current user
*
* @var \Throwable
*/
protected $userException;
/**
@@ -53,15 +86,13 @@ class Auth
* @param string $email
* @param bool $long If `true`, a long session will be created
* @param string $mode Either 'login' or 'password-reset'
* @return string|null Name of the challenge that was created;
* `null` if the user does not exist or no
* challenge was available for the user
* @return \Kirby\Cms\Auth\Status
*
* @throws \Kirby\Exception\LogicException If there is no suitable authentication challenge (only in debug mode)
* @throws \Kirby\Exception\NotFoundException If the user does not exist (only in debug mode)
* @throws \Kirby\Exception\PermissionException If the rate limit is exceeded
*/
public function createChallenge(string $email, bool $long = false, string $mode = 'login'): ?string
public function createChallenge(string $email, bool $long = false, string $mode = 'login')
{
// ensure that email addresses with IDN domains are in Unicode format
$email = Idn::decodeEmail($email);
@@ -91,8 +122,7 @@ class Auth
if ($user = $this->kirby->users()->find($email)) {
$timeout = $this->kirby->option('auth.challenge.timeout', 10 * 60);
$challenges = $this->kirby->option('auth.challenges', ['email']);
foreach (A::wrap($challenges) as $name) {
foreach ($this->enabledChallenges() as $name) {
$class = static::$challenges[$name] ?? null;
if (
$class &&
@@ -115,7 +145,7 @@ class Auth
}
// if no suitable challenge was found, `$challenge === null` at this point;
// only leak this in debug mode, otherwise `null` is returned below
// only leak this in debug mode
if ($challenge === null && $this->kirby->option('debug') === true) {
throw new LogicException('Could not find a suitable authentication challenge');
}
@@ -142,7 +172,10 @@ class Auth
// avoid leaking whether the user exists
usleep(random_int(1000, 300000));
return $challenge;
// clear the status cache
$this->status = null;
return $this->status($session, false);
}
/**
@@ -230,15 +263,7 @@ class Auth
*/
public function currentUserFromSession($session = null)
{
// use passed session options or session object if set
if (is_array($session) === true) {
$session = $this->kirby->session($session);
}
// try session in header or cookie
if (is_a($session, 'Kirby\Session\Session') === false) {
$session = $this->kirby->session(['detect' => true]);
}
$session = $this->session($session);
$id = $session->data()->get('kirby.userId');
@@ -256,6 +281,17 @@ class Auth
return null;
}
/**
* Returns the list of enabled challenges in the
* configured order
*
* @return array
*/
public function enabledChallenges(): array
{
return A::wrap($this->kirby->option('auth.challenges', ['email']));
}
/**
* Become any existing user or disable the current user
*
@@ -268,6 +304,9 @@ class Auth
*/
public function impersonate(?string $who = null)
{
// clear the status cache
$this->status = null;
switch ($who) {
case null:
return $this->impersonate = null;
@@ -359,6 +398,9 @@ class Auth
$user = $this->validatePassword($email, $password);
$user->loginPasswordless($options);
// clear the status cache
$this->status = null;
return $user;
}
@@ -368,8 +410,7 @@ class Auth
* @param string $email
* @param string $password
* @param bool $long
* @return string|null Name of the challenge that was created;
* `null` if no challenge was available for the user
* @return \Kirby\Cms\Auth\Status
*
* @throws \Kirby\Exception\PermissionException If the rate limit was exceeded or if any other error occured with debug mode off
* @throws \Kirby\Exception\NotFoundException If the email was invalid
@@ -394,6 +435,57 @@ class Auth
$this->impersonate = null;
$this->user = $user;
// clear the status cache
$this->status = null;
}
/**
* Returns the authentication status object
*
* @param \Kirby\Session\Session|array|null $session
* @param bool $allowImpersonation If set to false, only the actually
* logged in user will be returned
* @return \Kirby\Cms\Auth\Status
*/
public function status($session = null, bool $allowImpersonation = true)
{
// try to return from cache
if ($this->status && $session === null && $allowImpersonation === true) {
return $this->status;
}
$sessionObj = $this->session($session);
$props = ['kirby' => $this->kirby];
if ($user = $this->user($sessionObj, $allowImpersonation)) {
// a user is currently logged in
if ($allowImpersonation === true && $this->impersonate !== null) {
$props['status'] = 'impersonated';
} else {
$props['status'] = 'active';
}
$props['email'] = $user->email();
} elseif ($email = $sessionObj->get('kirby.challenge.email')) {
// a challenge is currently pending
$props['status'] = 'pending';
$props['email'] = $email;
$props['challenge'] = $sessionObj->get('kirby.challenge.type');
$props['challengeFallback'] = A::last($this->enabledChallenges());
} else {
// no active authentication
$props['status'] = 'inactive';
}
$status = new Status($props);
// only cache the default object
if ($session === null && $allowImpersonation === true) {
$this->status = $status;
}
return $status;
}
/**
@@ -534,6 +626,9 @@ class Auth
$session->remove('kirby.challenge.email');
$session->remove('kirby.challenge.timeout');
$session->remove('kirby.challenge.type');
// clear the status cache
$this->status = null;
}
/**
@@ -545,6 +640,7 @@ class Auth
public function flush(): void
{
$this->impersonate = null;
$this->status = null;
$this->user = null;
}
@@ -718,6 +814,9 @@ class Auth
$this->logout();
$user->loginPasswordless();
// clear the status cache
$this->status = null;
return $user;
} else {
throw new PermissionException(['key' => 'access.code']);
@@ -744,4 +843,25 @@ class Auth
}
}
}
/**
* Creates a session object from the passed options
*
* @param \Kirby\Session\Session|array|null $session
* @return \Kirby\Session\Session
*/
protected function session($session = null)
{
// use passed session options or session object if set
if (is_array($session) === true) {
return $this->kirby->session($session);
}
// try session in header or cookie
if (is_a($session, 'Kirby\Session\Session') === false) {
return $this->kirby->session(['detect' => true]);
}
return $session;
}
}

218
kirby/src/Cms/Auth/Status.php Executable file
View File

@@ -0,0 +1,218 @@
<?php
namespace Kirby\Cms\Auth;
use Kirby\Cms\App;
use Kirby\Exception\InvalidArgumentException;
use Kirby\Toolkit\Properties;
/**
* Information container for the
* authentication status
*
* @package Kirby Cms
* @author Lukas Bestle <lukas@getkirby.com>
* @link https://getkirby.com
* @copyright Bastian Allgeier GmbH
* @license https://getkirby.com/license
*/
class Status
{
use Properties;
/**
* Type of the active challenge
*
* @var string|null
*/
protected $challenge = null;
/**
* Challenge type to use as a fallback
* when $challenge is `null`
*
* @var string|null
*/
protected $challengeFallback = null;
/**
* Email address of the current/pending user
*
* @var string|null
*/
protected $email = null;
/**
* Kirby instance for user lookup
*
* @var \Kirby\Cms\App
*/
protected $kirby;
/**
* Authentication status:
* `active|impersonated|pending|inactive`
*
* @var string
*/
protected $status;
/**
* Class constructor
*
* @param array $props
*/
public function __construct(array $props)
{
$this->setProperties($props);
}
/**
* Returns the authentication status
*
* @return string
*/
public function __toString(): string
{
return $this->status();
}
/**
* Returns the type of the active challenge
*
* @param bool $automaticFallback If set to `false`, no faked challenge is returned;
* WARNING: never send the resulting `null` value to the
* user to avoid leaking whether the pending user exists
* @return string|null
*/
public function challenge(bool $automaticFallback = true): ?string
{
// never return a challenge type if the status doesn't match
if ($this->status() !== 'pending') {
return null;
}
if ($automaticFallback === false) {
return $this->challenge;
} else {
return $this->challenge ?? $this->challengeFallback;
}
}
/**
* Returns the email address of the current/pending user
*
* @return string|null
*/
public function email(): ?string
{
return $this->email;
}
/**
* Returns the authentication status
*
* @return string `active|impersonated|pending|inactive`
*/
public function status(): string
{
return $this->status;
}
/**
* Returns an array with all public status data
*
* @return array
*/
public function toArray(): array
{
return [
'challenge' => $this->challenge(),
'email' => $this->email(),
'status' => $this->status()
];
}
/**
* Returns the currently logged in user
*
* @return \Kirby\Cms\User
*/
public function user()
{
// for security, only return the user if they are
// already logged in
if (in_array($this->status(), ['active', 'impersonated']) !== true) {
return null;
}
return $this->kirby->user($this->email());
}
/**
* Sets the type of the active challenge
*
* @param string|null $challenge
* @return self
*/
protected function setChallenge(?string $challenge = null)
{
$this->challenge = $challenge;
return $this;
}
/**
* Sets the challenge type to use as
* a fallback when $challenge is `null`
*
* @param string|null $challengeFallback
* @return self
*/
protected function setChallengeFallback(?string $challengeFallback = null)
{
$this->challengeFallback = $challengeFallback;
return $this;
}
/**
* Sets the email address of the current/pending user
*
* @param string|null $email
* @return self
*/
protected function setEmail(?string $email = null)
{
$this->email = $email;
return $this;
}
/**
* Sets the Kirby instance for user lookup
*
* @param \Kirby\Cms\App $kirby
* @return self
*/
protected function setKirby(App $kirby)
{
$this->kirby = $kirby;
return $this;
}
/**
* Sets the authentication status
*
* @param string $status `active|impersonated|pending|inactive`
* @return self
*/
protected function setStatus(string $status)
{
if (in_array($status, ['active', 'impersonated', 'pending', 'inactive']) !== true) {
throw new InvalidArgumentException([
'data' => ['argument' => '$props[\'status\']', 'method' => 'Status::__construct']
]);
}
$this->status = $status;
return $this;
}
}

View File

@@ -194,7 +194,7 @@ class Block extends Item
* object. This can be used further
* with all available field methods
*
* @return \Kirby\Cms\Field;
* @return \Kirby\Cms\Field
*/
public function toField()
{

View File

@@ -74,7 +74,10 @@ class BlockConverter
'type' => 'list'
];
for ($x = $listStart+1; $x <= $listStart + count($list); $x++) {
$start = $listStart + 1;
$end = $listStart + count($list);
for ($x = $start; $x <= $end; $x++) {
$blocks[$x] = false;
}

View File

@@ -56,12 +56,12 @@ class Blocks extends Items
* @param array $params
* @return \Kirby\Cms\Blocks
*/
public static function factory(array $blocks = null, array $params = [])
public static function factory(array $items = null, array $params = [])
{
$blocks = static::extractFromLayouts($blocks);
$blocks = BlockConverter::editorBlocks($blocks);
$items = static::extractFromLayouts($items);
$items = BlockConverter::editorBlocks($items);
return parent::factory($blocks, $params);
return parent::factory($items, $params);
}
/**

View File

@@ -86,7 +86,7 @@ class Collection extends BaseCollection
*/
public function add($object)
{
if (is_a($object, static::class) === true) {
if (is_a($object, self::class) === true) {
$this->data = array_merge($this->data, $object->data);
} elseif (is_object($object) === true && method_exists($object, 'id') === true) {
$this->__set($object->id(), $object);

View File

@@ -50,7 +50,6 @@ class Fieldset extends Item
$this->disabled = $params['disabled'] ?? false;
$this->icon = $params['icon'] ?? null;
$this->model = $this->parent;
$this->kirby = $this->parent->kirby();
$this->name = $this->createName($params['name'] ?? Str::ucfirst($this->type));
$this->label = $this->createLabel($params['label'] ?? null);
$this->preview = $params['preview'] ?? null;
@@ -61,8 +60,8 @@ class Fieldset extends Item
if (
$this->translate === false &&
$this->kirby->multilang() === true &&
$this->kirby->language()->isDefault() === false
$this->kirby()->multilang() === true &&
$this->kirby()->language()->isDefault() === false
) {
// disable and unset the fieldset if it's not translatable
$this->unset = true;

View File

@@ -66,9 +66,9 @@ class Fieldsets extends Items
];
}
public static function factory(array $fieldsets = null, array $options = [])
public static function factory(array $items = null, array $params = [])
{
$fieldsets = $fieldsets ?? option('blocks.fieldsets', [
$items = $items ?? option('blocks.fieldsets', [
'code' => 'blocks/code',
'gallery' => 'blocks/gallery',
'heading' => 'blocks/heading',
@@ -80,9 +80,9 @@ class Fieldsets extends Items
'video' => 'blocks/video',
]);
$result = static::createFieldsets($fieldsets);
$result = static::createFieldsets($items);
return parent::factory($result['fieldsets'], ['groups' => $result['groups']] + $options);
return parent::factory($result['fieldsets'], ['groups' => $result['groups']] + $params);
}
public function groups(): array

View File

@@ -5,6 +5,7 @@ namespace Kirby\Cms;
use Kirby\Image\Image;
use Kirby\Toolkit\A;
use Kirby\Toolkit\F;
use Throwable;
/**
* The `$file` object provides a set
@@ -504,6 +505,31 @@ class File extends ModelWithContent
return parent::panelImageSource($query);
}
/**
* Returns an array of all actions
* that can be performed in the Panel
*
* @since 3.3.0 This also checks for the lock status
* @since 3.5.1 This also checks for matching accept settings
*
* @param array $unlock An array of options that will be force-unlocked
* @return array
*/
public function panelOptions(array $unlock = []): array
{
$options = parent::panelOptions($unlock);
try {
// check if the file type is allowed at all,
// otherwise it cannot be replaced
$this->match($this->blueprint()->accept());
} catch (Throwable $e) {
$options['replace'] = false;
}
return $options;
}
/**
* Returns the full path without leading slash
*
@@ -767,6 +793,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

@@ -191,7 +191,7 @@ trait FileModifications
return $this;
}
$result = $this->kirby()->component('file::version')($this->kirby(), $this, $options);
$result = ($this->kirby()->component('file::version'))($this->kirby(), $this, $options);
if (is_a($result, 'Kirby\Cms\FileVersion') === false && is_a($result, 'Kirby\Cms\File') === false) {
throw new InvalidArgumentException('The file::version component must return a File or FileVersion object');

View File

@@ -36,7 +36,7 @@ class Files extends Collection
public function add($object)
{
// add a page collection
if (is_a($object, static::class) === true) {
if (is_a($object, self::class) === true) {
$this->data = array_merge($this->data, $object->data);
// add a file by id

View File

@@ -33,6 +33,11 @@ class Item
*/
protected $params;
/**
* @var \Kirby\Cms\Page|\Kirby\Cms\Site|\Kirby\Cms\File|\Kirby\Cms\User
*/
protected $parent;
/**
* @var \Kirby\Cms\Items
*/
@@ -98,7 +103,7 @@ class Item
/**
* Returns the parent model
*
* @return \Kirby\Cms\Page | \Kirby\Cms\Site | \Kirby\Cms\File | \Kirby\Cms\User
* @return \Kirby\Cms\Page|\Kirby\Cms\Site|\Kirby\Cms\File|\Kirby\Cms\User
*/
public function parent()
{
@@ -109,7 +114,8 @@ class Item
* Returns the sibling collection
* This is required by the HasSiblings trait
*
* @return \Kirby\Editor\Blocks
* @return \Kirby\Cms\Items
* @psalm-return self::ITEMS_CLASS
*/
protected function siblingsCollection()
{

View File

@@ -40,6 +40,7 @@ class LanguageRoutes
// jump through to the fallback if nothing
// can be found for this language
/** @var \Kirby\Http\Route $this */
$this->next();
}
];

View File

@@ -15,25 +15,25 @@ class Layouts extends Items
{
const ITEM_CLASS = '\Kirby\Cms\Layout';
public static function factory(array $layouts = null, array $options = [])
public static function factory(array $items = null, array $params = [])
{
$first = $layouts[0] ?? [];
$first = $items[0] ?? [];
// if there are no wrapping layouts for blocks yet …
if (array_key_exists('content', $first) === true || array_key_exists('type', $first) === true) {
$layouts = [
$items = [
[
'id' => uuid(),
'columns' => [
[
'width' => '1/1',
'blocks' => $layouts
'blocks' => $items
]
]
]
];
}
return parent::factory($layouts, $options);
return parent::factory($items, $params);
}
}

View File

@@ -837,17 +837,17 @@ trait PageActions
* Updates the page data
*
* @param array|null $input
* @param string|null $language
* @param string|null $languageCode
* @param bool $validate
* @return self
*/
public function update(array $input = null, string $language = null, bool $validate = false)
public function update(array $input = null, string $languageCode = null, bool $validate = false)
{
if ($this->isDraft() === true) {
$validate = false;
}
$page = parent::update($input, $language, $validate);
$page = parent::update($input, $languageCode, $validate);
// if num is created from page content, update num on content update
if ($page->isListed() === true && in_array($page->blueprint()->num(), ['zero', 'default']) === false) {

View File

@@ -313,14 +313,14 @@ class PageRules
$drafts = $page->parentModel()->drafts();
$slug = $page->slug();
if ($duplicate = $siblings->find($slug)) {
if ($siblings->find($slug)) {
throw new DuplicateException([
'key' => 'page.duplicate',
'data' => ['slug' => $slug]
]);
}
if ($duplicate = $drafts->find($slug)) {
if ($drafts->find($slug)) {
throw new DuplicateException([
'key' => 'page.draft.duplicate',
'data' => ['slug' => $slug]

View File

@@ -48,7 +48,7 @@ class Pages extends Collection
public function add($object)
{
// add a page collection
if (is_a($object, static::class) === true) {
if (is_a($object, self::class) === true) {
$this->data = array_merge($this->data, $object->data);
// add a page by id
@@ -398,7 +398,7 @@ class Pages extends Collection
}
// merge an entire collection
if (is_a($args[0], static::class) === true) {
if (is_a($args[0], self::class) === true) {
$collection = clone $this;
$collection->data = array_merge($collection->data, $args[0]->data);
return $collection;

View File

@@ -28,7 +28,7 @@ class Panel
* Returns custom css path for panel ui
*
* @param \Kirby\Cms\App $kirby
* @return bool|string
* @return string|false
*/
public static function customCss(App $kirby)
{

View File

@@ -2,7 +2,6 @@
namespace Kirby\Cms;
use Kirby\Session\Session;
use Kirby\Toolkit\Facade;
/**

View File

@@ -37,7 +37,7 @@ class Search
public static function collection(Collection $collection, string $query = null, $params = [])
{
$kirby = App::instance();
return $kirby->component('search')($kirby, $collection, $query, $params);
return ($kirby->component('search'))($kirby, $collection, $query, $params);
}
/**

View File

@@ -44,6 +44,10 @@ class Section extends Component
throw new InvalidArgumentException('Undefined section model');
}
if (is_a($attrs['model'], 'Kirby\Cms\Model') === false) {
throw new InvalidArgumentException('Invalid section model');
}
// use the type as fallback for the name
$attrs['name'] = $attrs['name'] ?? $type;
$attrs['type'] = $type;
@@ -65,7 +69,7 @@ class Section extends Component
*/
public function kirby()
{
return $this->model->kirby();
return $this->model()->kirby();
}
/**

View File

@@ -62,8 +62,8 @@ class Url extends BaseUrl
{
$kirby = App::instance();
return $kirby->component('url')($kirby, $path, $options, function (string $path = null, $options = null) use ($kirby) {
return $kirby->nativeComponent('url')($kirby, $path, $options);
return ($kirby->component('url'))($kirby, $path, $options, function (string $path = null, $options = null) use ($kirby) {
return ($kirby->nativeComponent('url'))($kirby, $path, $options);
});
}
}

View File

@@ -400,7 +400,7 @@ class User extends ModelWithContent
*/
public function language(): string
{
return $this->language ?? $this->language = $this->credentials()['language'] ?? $this->kirby()->option('panel.language', 'en');
return $this->language ?? $this->language = $this->credentials()['language'] ?? $this->kirby()->panelLanguage();
}
/**

View File

@@ -302,13 +302,13 @@ trait UserActions
* Updates the user data
*
* @param array|null $input
* @param string|null $language
* @param string|null $languageCode
* @param bool $validate
* @return self
*/
public function update(array $input = null, string $language = null, bool $validate = false)
public function update(array $input = null, string $languageCode = null, bool $validate = false)
{
$user = parent::update($input, $language, $validate);
$user = parent::update($input, $languageCode, $validate);
// set auth user data only if the current user is this user
if ($user->isLoggedIn() === true) {

View File

@@ -43,7 +43,7 @@ class Users extends Collection
public function add($object)
{
// add a page collection
if (is_a($object, static::class) === true) {
if (is_a($object, self::class) === true) {
$this->data = array_merge($this->data, $object->data);
// add a user by id