Update Kirby and dependencies
This commit is contained in:
parent
750b9cc83e
commit
8c71a258b6
59 changed files with 2143 additions and 813 deletions
|
@ -10,6 +10,7 @@ use Kirby\Exception\NotFoundException;
|
|||
use Kirby\Filesystem\Dir;
|
||||
use Kirby\Filesystem\F;
|
||||
use Kirby\Http\Request;
|
||||
use Kirby\Http\Response;
|
||||
use Kirby\Http\Router;
|
||||
use Kirby\Http\Server;
|
||||
use Kirby\Http\Uri;
|
||||
|
@ -709,14 +710,25 @@ class App
|
|||
return $this->io(new NotFoundException());
|
||||
}
|
||||
|
||||
// Response Configuration
|
||||
// (Modified) global response configuration, e.g. in routes
|
||||
if (is_a($input, 'Kirby\Cms\Responder') === true) {
|
||||
// return the passed object unmodified (without injecting headers
|
||||
// from the global object) to allow a complete response override
|
||||
// https://github.com/getkirby/kirby/pull/4144#issuecomment-1034766726
|
||||
return $input->send();
|
||||
}
|
||||
|
||||
// Responses
|
||||
if (is_a($input, 'Kirby\Http\Response') === true) {
|
||||
return $input;
|
||||
$data = $input->toArray();
|
||||
|
||||
// inject headers from the global response configuration
|
||||
// lazily (only if they are not already set);
|
||||
// the case-insensitive nature of headers will be
|
||||
// handled by PHP's `header()` function
|
||||
$data['headers'] = array_merge($response->headers(), $data['headers']);
|
||||
|
||||
return new Response($data);
|
||||
}
|
||||
|
||||
// Pages
|
||||
|
|
|
@ -203,12 +203,14 @@ class Blueprint
|
|||
return $props;
|
||||
}
|
||||
|
||||
try {
|
||||
$mixin = static::find($extends);
|
||||
$mixin = static::extend($mixin);
|
||||
$props = A::merge($mixin, $props, A::MERGE_REPLACE);
|
||||
} catch (Exception $e) {
|
||||
// keep the props unextended if the snippet wasn't found
|
||||
foreach (A::wrap($extends) as $extend) {
|
||||
try {
|
||||
$mixin = static::find($extend);
|
||||
$mixin = static::extend($mixin);
|
||||
$props = A::merge($mixin, $props, A::MERGE_REPLACE);
|
||||
} catch (Exception $e) {
|
||||
// keep the props unextended if the snippet wasn't found
|
||||
}
|
||||
}
|
||||
|
||||
// remove the extends flag
|
||||
|
@ -287,13 +289,16 @@ class Blueprint
|
|||
$file = $kirby->extension('blueprints', $name);
|
||||
}
|
||||
|
||||
// callback option can be return array or blueprint file path
|
||||
if (is_callable($file) === true) {
|
||||
$file = $file($kirby);
|
||||
}
|
||||
|
||||
// now ensure that we always return the data array
|
||||
if (is_string($file) === true && F::exists($file) === true) {
|
||||
return static::$loaded[$name] = Data::read($file);
|
||||
} elseif (is_array($file) === true) {
|
||||
return static::$loaded[$name] = $file;
|
||||
} elseif (is_callable($file) === true) {
|
||||
return static::$loaded[$name] = $file($kirby);
|
||||
}
|
||||
|
||||
// neither a valid file nor array data
|
||||
|
|
|
@ -54,7 +54,7 @@ class Fieldset extends Item
|
|||
$this->editable = $params['editable'] ?? true;
|
||||
$this->icon = $params['icon'] ?? null;
|
||||
$this->model = $this->parent;
|
||||
$this->name = $this->createName($params['name'] ?? Str::ucfirst($this->type));
|
||||
$this->name = $this->createName($params['title'] ?? $params['name'] ?? Str::ucfirst($this->type));
|
||||
$this->label = $this->createLabel($params['label'] ?? null);
|
||||
$this->preview = $params['preview'] ?? null;
|
||||
$this->tabs = $this->createTabs($params);
|
||||
|
|
|
@ -353,12 +353,12 @@ class File extends ModelWithContent
|
|||
/**
|
||||
* Get the file's last modification time.
|
||||
*
|
||||
* @param string|null $format
|
||||
* @param string|null $handler date or strftime
|
||||
* @param string|\IntlDateFormatter|null $format
|
||||
* @param string|null $handler date, intl or strftime
|
||||
* @param string|null $languageCode
|
||||
* @return mixed
|
||||
*/
|
||||
public function modified(string $format = null, string $handler = null, string $languageCode = null)
|
||||
public function modified($format = null, string $handler = null, string $languageCode = null)
|
||||
{
|
||||
$file = $this->modifiedFile();
|
||||
$content = $this->modifiedContent($languageCode);
|
||||
|
|
|
@ -80,15 +80,30 @@ class FileRules
|
|||
*/
|
||||
public static function create(File $file, BaseFile $upload): bool
|
||||
{
|
||||
// We want to ensure that we are not creating duplicate files.
|
||||
// If a file with the same name already exists
|
||||
if ($file->exists() === true) {
|
||||
if ($file->sha1() !== $upload->sha1()) {
|
||||
throw new DuplicateException([
|
||||
'key' => 'file.duplicate',
|
||||
'data' => [
|
||||
'filename' => $file->filename()
|
||||
]
|
||||
]);
|
||||
// $file will be based on the props of the new file,
|
||||
// to compare templates, we need to get the props of
|
||||
// the already existing file from meta content file
|
||||
$existing = $file->parent()->file($file->filename());
|
||||
|
||||
// if the new upload is the exact same file
|
||||
// and uses the same template, we can continue
|
||||
if (
|
||||
$file->sha1() === $upload->sha1() &&
|
||||
$file->template() === $existing->template()
|
||||
) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// otherwise throw an error for duplicate file
|
||||
throw new DuplicateException([
|
||||
'key' => 'file.duplicate',
|
||||
'data' => [
|
||||
'filename' => $file->filename()
|
||||
]
|
||||
]);
|
||||
}
|
||||
|
||||
if ($file->permissions()->create() !== true) {
|
||||
|
|
|
@ -347,6 +347,7 @@ abstract class ModelWithContent extends Model
|
|||
$result = Str::query($query, [
|
||||
'kirby' => $this->kirby(),
|
||||
'site' => is_a($this, 'Kirby\Cms\Site') ? $this : $this->site(),
|
||||
'model' => $this,
|
||||
static::CLASS_ALIAS => $this
|
||||
]);
|
||||
} catch (Throwable $e) {
|
||||
|
|
|
@ -25,7 +25,7 @@ class PageBlueprint extends Blueprint
|
|||
|
||||
// normalize all available page options
|
||||
$this->props['options'] = $this->normalizeOptions(
|
||||
$props['options'] ?? true,
|
||||
$this->props['options'] ?? true,
|
||||
// defaults
|
||||
[
|
||||
'changeSlug' => null,
|
||||
|
@ -50,10 +50,10 @@ class PageBlueprint extends Blueprint
|
|||
);
|
||||
|
||||
// normalize the ordering number
|
||||
$this->props['num'] = $this->normalizeNum($props['num'] ?? 'default');
|
||||
$this->props['num'] = $this->normalizeNum($this->props['num'] ?? 'default');
|
||||
|
||||
// normalize the available status array
|
||||
$this->props['status'] = $this->normalizeStatus($props['status'] ?? null);
|
||||
$this->props['status'] = $this->normalizeStatus($this->props['status'] ?? null);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -97,14 +97,20 @@ class Roles extends Collection
|
|||
*/
|
||||
public static function load(string $root = null, array $inject = [])
|
||||
{
|
||||
$kirby = App::instance();
|
||||
$roles = new static();
|
||||
|
||||
// load roles from plugins
|
||||
foreach (App::instance()->extensions('blueprints') as $blueprintName => $blueprint) {
|
||||
foreach ($kirby->extensions('blueprints') as $blueprintName => $blueprint) {
|
||||
if (substr($blueprintName, 0, 6) !== 'users/') {
|
||||
continue;
|
||||
}
|
||||
|
||||
// callback option can be return array or blueprint file path
|
||||
if (is_callable($blueprint) === true) {
|
||||
$blueprint = $blueprint($kirby);
|
||||
}
|
||||
|
||||
if (is_array($blueprint) === true) {
|
||||
$role = Role::factory($blueprint, $inject);
|
||||
} else {
|
||||
|
|
|
@ -26,7 +26,7 @@ class SiteBlueprint extends Blueprint
|
|||
|
||||
// normalize all available page options
|
||||
$this->props['options'] = $this->normalizeOptions(
|
||||
$props['options'] ?? true,
|
||||
$this->props['options'] ?? true,
|
||||
// defaults
|
||||
[
|
||||
'changeTitle' => null,
|
||||
|
|
|
@ -445,7 +445,7 @@ class System
|
|||
}
|
||||
|
||||
// @codeCoverageIgnoreStart
|
||||
$response = Remote::get('https://licenses.getkirby.com/register', [
|
||||
$response = Remote::get('https://hub.getkirby.com/register', [
|
||||
'data' => [
|
||||
'license' => $license,
|
||||
'email' => Str::lower(trim($email)),
|
||||
|
|
|
@ -30,7 +30,7 @@ class UserBlueprint extends Blueprint
|
|||
|
||||
// normalize all available page options
|
||||
$this->props['options'] = $this->normalizeOptions(
|
||||
$props['options'] ?? true,
|
||||
$this->props['options'] ?? true,
|
||||
// defaults
|
||||
[
|
||||
'create' => null,
|
||||
|
|
|
@ -775,7 +775,11 @@ class Query
|
|||
|
||||
// apply it to the dataset and retrieve all rows. make sure to use Collection as the iterator to be able to attach the pagination object
|
||||
$iterator = $this->iterator;
|
||||
$collection = $this->offset($pagination->offset())->limit($pagination->limit())->iterator('Collection')->all();
|
||||
$collection = $this
|
||||
->offset($pagination->offset())
|
||||
->limit($pagination->limit())
|
||||
->iterator('Kirby\Toolkit\Collection')
|
||||
->all();
|
||||
|
||||
$this->iterator($iterator);
|
||||
|
||||
|
@ -968,6 +972,11 @@ class Query
|
|||
$this->bindings($sql['bindings']);
|
||||
} elseif (is_callable($args[0]) === true) {
|
||||
$query = clone $this;
|
||||
|
||||
// since the callback uses its own where condition
|
||||
// it is necessary to clear/reset the cloned where condition
|
||||
$query->where = null;
|
||||
|
||||
call_user_func($args[0], $query);
|
||||
|
||||
// copy over the bindings from the nested query
|
||||
|
|
|
@ -853,8 +853,14 @@ abstract class Sql
|
|||
$query = [];
|
||||
$bindings = [];
|
||||
|
||||
foreach ($values as $key => $value) {
|
||||
$fields[] = $this->columnName($table, $key, $enforceQualified);
|
||||
foreach ($values as $column => $value) {
|
||||
$key = $this->columnName($table, $column, $enforceQualified);
|
||||
|
||||
if ($key === null) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$fields[] = $key;
|
||||
|
||||
if (in_array($value, static::$literals, true) === true) {
|
||||
$query[] = $value ?: 'null';
|
||||
|
@ -896,6 +902,10 @@ abstract class Sql
|
|||
foreach ($values as $column => $value) {
|
||||
$key = $this->columnName($table, $column, $enforceQualified);
|
||||
|
||||
if ($key === null) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (in_array($value, static::$literals, true) === true) {
|
||||
$query[] = $key . ' = ' . ($value ?: 'null');
|
||||
continue;
|
||||
|
|
|
@ -137,7 +137,7 @@ class Sqlite extends Sql
|
|||
public function tables(): array
|
||||
{
|
||||
return [
|
||||
'query' => 'SELECT name FROM sqlite_master WHERE type = "table"',
|
||||
'query' => 'SELECT name FROM sqlite_master WHERE type = "table" OR type = "view"',
|
||||
'bindings' => []
|
||||
];
|
||||
}
|
||||
|
|
|
@ -463,11 +463,11 @@ class F
|
|||
* Get the file's last modification time.
|
||||
*
|
||||
* @param string $file
|
||||
* @param string $format
|
||||
* @param string $handler date or strftime
|
||||
* @param string|\IntlDateFormatter|null $format
|
||||
* @param string $handler date, intl or strftime
|
||||
* @return mixed
|
||||
*/
|
||||
public static function modified(string $file, string $format = null, string $handler = 'date')
|
||||
public static function modified(string $file, $format = null, string $handler = 'date')
|
||||
{
|
||||
if (file_exists($file) !== true) {
|
||||
return false;
|
||||
|
|
|
@ -372,11 +372,11 @@ class File
|
|||
/**
|
||||
* Returns the file's last modification time
|
||||
*
|
||||
* @param string $format
|
||||
* @param string|null $handler date or strftime
|
||||
* @param string|\IntlDateFormatter|null $format
|
||||
* @param string|null $handler date, intl or strftime
|
||||
* @return mixed
|
||||
*/
|
||||
public function modified(?string $format = null, ?string $handler = null)
|
||||
public function modified($format = null, ?string $handler = null)
|
||||
{
|
||||
$kirby = $this->kirby();
|
||||
|
||||
|
|
|
@ -268,7 +268,14 @@ class Server
|
|||
public static function requestUri(): array
|
||||
{
|
||||
$uri = static::get('REQUEST_URI', '');
|
||||
$uri = parse_url($uri);
|
||||
|
||||
if (Url::isAbsolute($uri) === true) {
|
||||
$uri = parse_url($uri);
|
||||
} else {
|
||||
// the fake domain is needed to make sure the URL parsing is
|
||||
// always correct. Even if there's a colon in the path for params
|
||||
$uri = parse_url('http://getkirby.com' . $uri);
|
||||
}
|
||||
|
||||
return [
|
||||
'path' => $uri['path'] ?? null,
|
||||
|
|
|
@ -130,7 +130,7 @@ class Uri
|
|||
* Creates a new URI object
|
||||
*
|
||||
* @param array|string $props
|
||||
* @param array $inject
|
||||
* @param array $inject Additional props to inject if a URL string is passed
|
||||
*/
|
||||
public function __construct($props = [], array $inject = [])
|
||||
{
|
||||
|
@ -144,10 +144,7 @@ class Uri
|
|||
|
||||
// parse the path and extract params
|
||||
if (empty($props['path']) === false) {
|
||||
$extract = Params::extract($props['path']);
|
||||
$props['params'] ??= $extract['params'];
|
||||
$props['path'] = $extract['path'];
|
||||
$props['slash'] ??= $extract['slash'];
|
||||
$props = static::parsePath($props);
|
||||
}
|
||||
|
||||
$this->setProperties($this->props = $props);
|
||||
|
@ -372,11 +369,17 @@ class Uri
|
|||
}
|
||||
|
||||
/**
|
||||
* @param \Kirby\Http\Params|string|array|null $params
|
||||
* @param \Kirby\Http\Params|string|array|false|null $params
|
||||
* @return $this
|
||||
*/
|
||||
public function setParams($params = null)
|
||||
{
|
||||
// ensure that the special constructor value of `false`
|
||||
// is never passed through as it's not supported by `Params`
|
||||
if ($params === false) {
|
||||
$params = [];
|
||||
}
|
||||
|
||||
$this->params = is_a($params, 'Kirby\Http\Params') === true ? $params : new Params($params);
|
||||
return $this;
|
||||
}
|
||||
|
@ -539,4 +542,33 @@ class Uri
|
|||
}
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses the path inside the props and extracts
|
||||
* the params unless disabled
|
||||
*
|
||||
* @param array $props
|
||||
* @return array Modified props array
|
||||
*/
|
||||
protected static function parsePath(array $props): array
|
||||
{
|
||||
// extract params, the rest is the path;
|
||||
// only do this if not explicitly disabled (set to `false`)
|
||||
if (isset($props['params']) === false || $props['params'] !== false) {
|
||||
$extract = Params::extract($props['path']);
|
||||
$props['params'] ??= $extract['params'];
|
||||
$props['path'] = $extract['path'];
|
||||
$props['slash'] ??= $extract['slash'];
|
||||
|
||||
return $props;
|
||||
}
|
||||
|
||||
// use the full path;
|
||||
// automatically detect the trailing slash from it if possible
|
||||
if (is_string($props['path']) === true) {
|
||||
$props['slash'] = substr($props['path'], -1, 1) === '/';
|
||||
}
|
||||
|
||||
return $props;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -16,6 +16,11 @@ use Throwable;
|
|||
*/
|
||||
class File extends Model
|
||||
{
|
||||
/**
|
||||
* @var \Kirby\Cms\File
|
||||
*/
|
||||
protected $model;
|
||||
|
||||
/**
|
||||
* Breadcrumb array
|
||||
*
|
||||
|
@ -423,11 +428,11 @@ class File extends Model
|
|||
return [
|
||||
'next' => function () use ($file, $siblings): ?array {
|
||||
$next = $siblings->nth($siblings->indexOf($file) + 1);
|
||||
return $next ? $next->panel()->toLink('filename') : null;
|
||||
return $this->toPrevNextLink($next, 'filename');
|
||||
},
|
||||
'prev' => function () use ($file, $siblings): ?array {
|
||||
$prev = $siblings->nth($siblings->indexOf($file) - 1);
|
||||
return $prev ? $prev->panel()->toLink('filename') : null;
|
||||
return $this->toPrevNextLink($prev, 'filename');
|
||||
}
|
||||
];
|
||||
}
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
namespace Kirby\Panel;
|
||||
|
||||
use Kirby\Form\Form;
|
||||
use Kirby\Http\Uri;
|
||||
use Kirby\Toolkit\A;
|
||||
|
||||
/**
|
||||
|
@ -387,6 +388,36 @@ abstract class Model
|
|||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns link url and tooltip
|
||||
* for optional sibling model and
|
||||
* preserves tab selection
|
||||
*
|
||||
* @internal
|
||||
*
|
||||
* @param \Kirby\Cms\ModelWithContent|null $model
|
||||
* @param string $tooltip
|
||||
* @return array
|
||||
*/
|
||||
protected function toPrevNextLink($model = null, string $tooltip = 'title'): ?array
|
||||
{
|
||||
if ($model === null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$data = $model->panel()->toLink($tooltip);
|
||||
|
||||
if ($tab = get('tab')) {
|
||||
$uri = new Uri($data['link'], [
|
||||
'query' => ['tab' => $tab]
|
||||
]);
|
||||
|
||||
$data['link'] = $uri->toString();
|
||||
}
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the url to the editing view
|
||||
* in the Panel
|
||||
|
|
|
@ -14,6 +14,11 @@ namespace Kirby\Panel;
|
|||
*/
|
||||
class Page extends Model
|
||||
{
|
||||
/**
|
||||
* @var \Kirby\Cms\Page
|
||||
*/
|
||||
protected $model;
|
||||
|
||||
/**
|
||||
* Breadcrumb array
|
||||
*
|
||||
|
@ -309,14 +314,8 @@ class Page extends Model
|
|||
};
|
||||
|
||||
return [
|
||||
'next' => function () use ($siblings) {
|
||||
$next = $siblings('next')->first();
|
||||
return $next ? $next->panel()->toLink('title') : null;
|
||||
},
|
||||
'prev' => function () use ($siblings) {
|
||||
$prev = $siblings('prev')->last();
|
||||
return $prev ? $prev->panel()->toLink('title') : null;
|
||||
}
|
||||
'next' => fn () => $this->toPrevNextLink($siblings('next')->first()),
|
||||
'prev' => fn () => $this->toPrevNextLink($siblings('prev')->last())
|
||||
];
|
||||
}
|
||||
|
||||
|
|
|
@ -14,6 +14,11 @@ namespace Kirby\Panel;
|
|||
*/
|
||||
class Site extends Model
|
||||
{
|
||||
/**
|
||||
* @var \Kirby\Cms\Site
|
||||
*/
|
||||
protected $model;
|
||||
|
||||
/**
|
||||
* Returns the setup for a dropdown option
|
||||
* which is used in the changes dropdown
|
||||
|
|
|
@ -14,6 +14,11 @@ namespace Kirby\Panel;
|
|||
*/
|
||||
class User extends Model
|
||||
{
|
||||
/**
|
||||
* @var \Kirby\Cms\User
|
||||
*/
|
||||
protected $model;
|
||||
|
||||
/**
|
||||
* Breadcrumb array
|
||||
*
|
||||
|
@ -193,14 +198,8 @@ class User extends Model
|
|||
$user = $this->model;
|
||||
|
||||
return [
|
||||
'next' => function () use ($user) {
|
||||
$next = $user->next();
|
||||
return $next ? $next->panel()->toLink('username') : null;
|
||||
},
|
||||
'prev' => function () use ($user) {
|
||||
$prev = $user->prev();
|
||||
return $prev ? $prev->panel()->toLink('username') : null;
|
||||
}
|
||||
'next' => fn () => $this->toPrevNextLink($user->next(), 'username'),
|
||||
'prev' => fn () => $this->toPrevNextLink($user->prev(), 'username')
|
||||
];
|
||||
}
|
||||
|
||||
|
|
|
@ -335,6 +335,29 @@ class A
|
|||
return array_pop($array);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a number of random elements from an array,
|
||||
* either in original or shuffled order
|
||||
*
|
||||
* @param array $array
|
||||
* @param int $count
|
||||
* @param bool $shuffle
|
||||
* @return array
|
||||
*/
|
||||
public static function random(array $array, int $count = 1, bool $shuffle = false): array
|
||||
{
|
||||
if ($shuffle) {
|
||||
return array_slice(self::shuffle($array), 0, $count);
|
||||
}
|
||||
|
||||
if ($count === 1) {
|
||||
$key = array_rand($array);
|
||||
return [$key => $array[$key]];
|
||||
}
|
||||
|
||||
return self::get($array, array_rand($array, $count));
|
||||
}
|
||||
|
||||
/**
|
||||
* Fills an array up with additional elements to certain amount.
|
||||
*
|
||||
|
@ -726,4 +749,37 @@ class A
|
|||
return $array;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Filter the array using the given callback
|
||||
* using both value and key
|
||||
* @since 3.6.5
|
||||
*
|
||||
* @param array $array
|
||||
* @param callable $callback
|
||||
* @return array
|
||||
*/
|
||||
public static function filter(array $array, callable $callback): array
|
||||
{
|
||||
return array_filter($array, $callback, ARRAY_FILTER_USE_BOTH);
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove key(s) from an array
|
||||
* @since 3.6.5
|
||||
*
|
||||
* @param array $array
|
||||
* @param int|string|array $keys
|
||||
* @return array
|
||||
*/
|
||||
public static function without(array $array, $keys): array
|
||||
{
|
||||
if (is_int($keys) || is_string($keys)) {
|
||||
$keys = static::wrap($keys);
|
||||
}
|
||||
|
||||
return static::filter($array, function ($value, $key) use ($keys) {
|
||||
return in_array($key, $keys, true) === false;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
@ -870,6 +870,25 @@ class Collection extends Iterator implements Countable
|
|||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a new collection consisting of random elements,
|
||||
* from the original collection, shuffled or ordered
|
||||
*
|
||||
* @param int $count
|
||||
* @param bool $shuffle
|
||||
* @return static
|
||||
*/
|
||||
public function random(int $count = 1, bool $shuffle = false)
|
||||
{
|
||||
if ($shuffle) {
|
||||
return $this->shuffle()->slice(0, $count);
|
||||
}
|
||||
|
||||
$collection = clone $this;
|
||||
$collection->data = A::random($collection->data, $count);
|
||||
return $collection;
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes an element from the array by key
|
||||
*
|
||||
|
|
|
@ -500,11 +500,7 @@ class Html extends Xml
|
|||
($attr['allowfullscreen'] ?? true) === true
|
||||
) {
|
||||
$attr['allow'] = 'fullscreen';
|
||||
}
|
||||
|
||||
// remove deprecated attribute
|
||||
if (isset($attr['allowfullscreen']) === true) {
|
||||
unset($attr['allowfullscreen']);
|
||||
$attr['allowfullscreen'] = true;
|
||||
}
|
||||
|
||||
return $attr;
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
|
||||
namespace Kirby\Toolkit;
|
||||
|
||||
use Kirby\Exception\InvalidArgumentException;
|
||||
use stdClass;
|
||||
|
||||
/**
|
||||
|
@ -62,14 +63,31 @@ class Obj extends stdClass
|
|||
}
|
||||
|
||||
/**
|
||||
* Property Getter
|
||||
* Gets one or multiple properties of the object
|
||||
*
|
||||
* @param string $property
|
||||
* @param mixed $fallback
|
||||
* @param string|array $property
|
||||
* @param mixed $fallback If multiple properties are requested:
|
||||
* Associative array of fallback values per key
|
||||
* @return mixed
|
||||
*/
|
||||
public function get(string $property, $fallback = null)
|
||||
public function get($property, $fallback = null)
|
||||
{
|
||||
if (is_array($property)) {
|
||||
if ($fallback === null) {
|
||||
$fallback = [];
|
||||
}
|
||||
|
||||
if (!is_array($fallback)) {
|
||||
throw new InvalidArgumentException('The fallback value must be an array when getting multiple properties');
|
||||
}
|
||||
|
||||
$result = [];
|
||||
foreach ($property as $key) {
|
||||
$result[$key] = $this->$key ?? $fallback[$key] ?? null;
|
||||
}
|
||||
return $result;
|
||||
}
|
||||
|
||||
return $this->$property ?? $fallback;
|
||||
}
|
||||
|
||||
|
|
|
@ -75,7 +75,12 @@ class Pagination
|
|||
|
||||
$params = [];
|
||||
|
||||
if (is_array($a) === true) {
|
||||
if (is_a($a, static::class) === true) {
|
||||
/**
|
||||
* First argument is a pagination/self object
|
||||
*/
|
||||
return $a;
|
||||
} elseif (is_array($a) === true) {
|
||||
|
||||
/**
|
||||
* First argument is an option array
|
||||
|
|
|
@ -2,7 +2,9 @@
|
|||
|
||||
namespace Kirby\Toolkit;
|
||||
|
||||
use DateTime;
|
||||
use Exception;
|
||||
use IntlDateFormatter;
|
||||
use Kirby\Exception\InvalidArgumentException;
|
||||
|
||||
/**
|
||||
|
@ -264,17 +266,33 @@ class Str
|
|||
* according to locale settings
|
||||
*
|
||||
* @param int|null $time
|
||||
* @param string|null $format
|
||||
* @param string $handler date or strftime
|
||||
* @param string|\IntlDateFormatter|null $format
|
||||
* @param string $handler date, intl or strftime
|
||||
* @return string|int
|
||||
*/
|
||||
public static function date(?int $time = null, ?string $format = null, string $handler = 'date')
|
||||
public static function date(?int $time = null, $format = null, string $handler = 'date')
|
||||
{
|
||||
if (is_null($format) === true) {
|
||||
return $time;
|
||||
}
|
||||
|
||||
// separately handle strftime to be able
|
||||
// $format is an IntlDateFormatter instance
|
||||
if (is_a($format, 'IntlDateFormatter') === true) {
|
||||
return $format->format($time ?? time());
|
||||
}
|
||||
|
||||
// `intl` handler
|
||||
if ($handler === 'intl') {
|
||||
$datetime = new DateTime();
|
||||
|
||||
if ($time !== null) {
|
||||
$datetime->setTimestamp($time);
|
||||
}
|
||||
|
||||
return IntlDateFormatter::formatObject($datetime, $format);
|
||||
}
|
||||
|
||||
// handle `strftime` to be able
|
||||
// to suppress deprecation warning
|
||||
// TODO: remove strftime support for PHP 9.0
|
||||
if ($handler === 'strftime') {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue