init with kirby, vue and pagedjs interactive
This commit is contained in:
commit
dc0ae26464
968 changed files with 211706 additions and 0 deletions
124
public/kirby/src/Plugin/Asset.php
Normal file
124
public/kirby/src/Plugin/Asset.php
Normal file
|
|
@ -0,0 +1,124 @@
|
|||
<?php
|
||||
|
||||
namespace Kirby\Plugin;
|
||||
|
||||
use Kirby\Filesystem\F;
|
||||
use Stringable;
|
||||
|
||||
/**
|
||||
* Representing a plugin asset with methods
|
||||
* to manage the asset file between the plugin
|
||||
* and media folder
|
||||
*
|
||||
* @package Kirby Plugin
|
||||
* @author Nico Hoffmann <nico@getkirby.com>
|
||||
* @link https://getkirby.com
|
||||
* @copyright Bastian Allgeier
|
||||
* @license https://getkirby.com/license
|
||||
*/
|
||||
class Asset implements Stringable
|
||||
{
|
||||
public function __construct(
|
||||
protected string $path,
|
||||
protected string $root,
|
||||
protected Plugin $plugin
|
||||
) {
|
||||
}
|
||||
|
||||
public function extension(): string
|
||||
{
|
||||
return F::extension($this->path());
|
||||
}
|
||||
|
||||
public function filename(): string
|
||||
{
|
||||
return F::filename($this->path());
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a unique media hash
|
||||
*/
|
||||
public function mediaHash(): string
|
||||
{
|
||||
return crc32($this->filename()) . '-' . $this->modified();
|
||||
}
|
||||
|
||||
/**
|
||||
* Absolute path to the asset file in the media folder
|
||||
*/
|
||||
public function mediaRoot(): string
|
||||
{
|
||||
return $this->plugin()->mediaRoot() . '/' . $this->mediaHash() . '/' . $this->path();
|
||||
}
|
||||
|
||||
/**
|
||||
* Public accessible url path for the asset
|
||||
*/
|
||||
public function mediaUrl(): string
|
||||
{
|
||||
return $this->plugin()->mediaUrl() . '/' . $this->mediaHash() . '/' . $this->path();
|
||||
}
|
||||
|
||||
/**
|
||||
* Timestamp when asset file was last modified
|
||||
*/
|
||||
public function modified(): int|false
|
||||
{
|
||||
return F::modified($this->root());
|
||||
}
|
||||
|
||||
public function path(): string
|
||||
{
|
||||
return $this->path;
|
||||
}
|
||||
|
||||
public function plugin(): Plugin
|
||||
{
|
||||
return $this->plugin;
|
||||
}
|
||||
|
||||
/**
|
||||
* Publishes the asset file to the plugin's media folder
|
||||
* by creating a symlink
|
||||
*/
|
||||
public function publish(): void
|
||||
{
|
||||
F::link($this->root(), $this->mediaRoot(), 'symlink');
|
||||
}
|
||||
|
||||
/**
|
||||
* @internal
|
||||
* @since 4.0.0
|
||||
* @deprecated 4.0.0
|
||||
* @codeCoverageIgnore
|
||||
*/
|
||||
public function publishAt(string $path): void
|
||||
{
|
||||
F::link(
|
||||
$this->root(),
|
||||
$this->plugin()->mediaRoot() . '/' . $path,
|
||||
'symlink'
|
||||
);
|
||||
}
|
||||
|
||||
public function root(): string
|
||||
{
|
||||
return $this->root;
|
||||
}
|
||||
|
||||
/**
|
||||
* @see self::mediaUrl()
|
||||
*/
|
||||
public function url(): string
|
||||
{
|
||||
return $this->mediaUrl();
|
||||
}
|
||||
|
||||
/**
|
||||
* @see self::url()
|
||||
*/
|
||||
public function __toString(): string
|
||||
{
|
||||
return $this->url();
|
||||
}
|
||||
}
|
||||
188
public/kirby/src/Plugin/Assets.php
Normal file
188
public/kirby/src/Plugin/Assets.php
Normal file
|
|
@ -0,0 +1,188 @@
|
|||
<?php
|
||||
|
||||
namespace Kirby\Plugin;
|
||||
|
||||
use Closure;
|
||||
use Kirby\Cms\App;
|
||||
use Kirby\Cms\Collection;
|
||||
use Kirby\Filesystem\Dir;
|
||||
use Kirby\Filesystem\F;
|
||||
use Kirby\Http\Response;
|
||||
use Kirby\Toolkit\Str;
|
||||
|
||||
/**
|
||||
* Plugin assets are automatically copied/linked
|
||||
* to the media folder, to make them publicly
|
||||
* available. This class handles the magic around that.
|
||||
*
|
||||
* @package Kirby Plugin
|
||||
* @author Bastian Allgeier <bastian@getkirby.com>
|
||||
* @author Nico Hoffmann <nico@getkirby.com>
|
||||
* @link https://getkirby.com
|
||||
* @copyright Bastian Allgeier
|
||||
* @license https://getkirby.com/license
|
||||
*
|
||||
* @extends \Kirby\Cms\Collection<\Kirby\Plugin\Asset>
|
||||
*/
|
||||
class Assets extends Collection
|
||||
{
|
||||
/**
|
||||
* Clean old/deprecated assets on every resolve
|
||||
*/
|
||||
public static function clean(string $pluginName): void
|
||||
{
|
||||
if ($plugin = App::instance()->plugin($pluginName)) {
|
||||
$media = $plugin->mediaRoot();
|
||||
$assets = $plugin->assets();
|
||||
|
||||
// get all media files
|
||||
$files = Dir::index($media, true);
|
||||
|
||||
// get all active assets' paths from the plugin
|
||||
$active = $assets->values(
|
||||
function ($asset) {
|
||||
$path = $asset->mediaHash() . '/' . $asset->path();
|
||||
$paths = [];
|
||||
$parts = explode('/', $path);
|
||||
|
||||
// collect all path segments
|
||||
// (e.g. foo/, foo/bar/, foo/bar/baz.css) for the asset
|
||||
for ($i = 1, $max = count($parts); $i <= $max; $i++) {
|
||||
$paths[] = implode('/', array_slice($parts, 0, $i));
|
||||
|
||||
// TODO: remove when media hash is enforced as mandatory
|
||||
$paths[] = implode('/', array_slice($parts, 1, $i));
|
||||
}
|
||||
|
||||
return $paths;
|
||||
}
|
||||
);
|
||||
|
||||
// flatten the array and remove duplicates
|
||||
$active = array_unique(array_merge(...array_values($active)));
|
||||
|
||||
// get outdated media files by comparing all
|
||||
// files in the media folder against the set of asset paths
|
||||
$stale = array_diff($files, $active);
|
||||
|
||||
foreach ($stale as $file) {
|
||||
$root = $media . '/' . $file;
|
||||
|
||||
if (is_file($root) === true) {
|
||||
F::remove($root);
|
||||
} else {
|
||||
Dir::remove($root);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Filters assets collection by CSS files
|
||||
*/
|
||||
public function css(): static
|
||||
{
|
||||
return $this->filter(fn ($asset) => $asset->extension() === 'css');
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new collection for the plugin's assets
|
||||
* by considering the plugin's `asset` extension
|
||||
* (and `assets` directory as fallback)
|
||||
*/
|
||||
public static function factory(Plugin $plugin): static
|
||||
{
|
||||
// get assets defined in the plugin extension
|
||||
if ($assets = $plugin->extends()['assets'] ?? null) {
|
||||
if ($assets instanceof Closure) {
|
||||
$assets = $assets();
|
||||
}
|
||||
|
||||
// normalize array: use relative path as
|
||||
// key when no key is defined
|
||||
foreach ($assets as $key => $root) {
|
||||
if (is_int($key) === true) {
|
||||
unset($assets[$key]);
|
||||
$path = Str::after($root, $plugin->root() . '/');
|
||||
$assets[$path] = $root;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// fallback: if no assets are defined in the plugin extension,
|
||||
// use all files in the plugin's `assets` directory
|
||||
if ($assets === null) {
|
||||
$assets = [];
|
||||
$root = $plugin->root() . '/assets';
|
||||
|
||||
foreach (Dir::index($root, true) as $path) {
|
||||
if (is_file($root . '/' . $path) === true) {
|
||||
$assets[$path] = $root . '/' . $path;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$collection = new static([], $plugin);
|
||||
|
||||
foreach ($assets as $path => $root) {
|
||||
$collection->data[$path] = new Asset($path, $root, $plugin);
|
||||
}
|
||||
|
||||
return $collection;
|
||||
}
|
||||
|
||||
/**
|
||||
* Filters assets collection by JavaScript files
|
||||
*/
|
||||
public function js(): static
|
||||
{
|
||||
return $this->filter(fn ($asset) => $asset->extension() === 'js');
|
||||
}
|
||||
|
||||
public function plugin(): Plugin
|
||||
{
|
||||
return $this->parent;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a symlink for a plugin asset and
|
||||
* return the public URL
|
||||
*/
|
||||
public static function resolve(
|
||||
string $pluginName,
|
||||
string $hash,
|
||||
string $path
|
||||
): Response|null {
|
||||
if ($plugin = App::instance()->plugin($pluginName)) {
|
||||
// do some spring cleaning for older files
|
||||
static::clean($pluginName);
|
||||
|
||||
// @codeCoverageIgnoreStart
|
||||
// TODO: deprecated media URL without hash
|
||||
if (empty($hash) === true) {
|
||||
$asset = $plugin->asset($path);
|
||||
$asset->publishAt($path);
|
||||
return Response::file($asset->root());
|
||||
}
|
||||
|
||||
// TODO: deprecated media URL with hash (but path)
|
||||
if ($asset = $plugin->asset($hash . '/' . $path)) {
|
||||
$asset->publishAt($hash . '/' . $path);
|
||||
return Response::file($asset->root());
|
||||
}
|
||||
// @codeCoverageIgnoreEnd
|
||||
|
||||
if ($asset = $plugin->asset($path)) {
|
||||
if ($asset->mediaHash() === $hash) {
|
||||
// create a symlink if possible
|
||||
$asset->publish();
|
||||
|
||||
// return the file response
|
||||
return Response::file($asset->root());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
112
public/kirby/src/Plugin/License.php
Normal file
112
public/kirby/src/Plugin/License.php
Normal file
|
|
@ -0,0 +1,112 @@
|
|||
<?php
|
||||
|
||||
namespace Kirby\Plugin;
|
||||
|
||||
use Closure;
|
||||
use Stringable;
|
||||
|
||||
/**
|
||||
* Represents the license of a plugin.
|
||||
* Used to display the license in the Panel system view
|
||||
*
|
||||
* @package Kirby Plugin
|
||||
* @author Bastian Allgeier <bastian@getkirby.com>
|
||||
* @link https://getkirby.com
|
||||
* @copyright Bastian Allgeier
|
||||
* @license https://getkirby.com/license
|
||||
* @since 5.0.0
|
||||
*/
|
||||
class License implements Stringable
|
||||
{
|
||||
protected LicenseStatus $status;
|
||||
|
||||
public function __construct(
|
||||
protected Plugin $plugin,
|
||||
protected string $name,
|
||||
protected string|null $link = null,
|
||||
LicenseStatus|null $status = null
|
||||
) {
|
||||
$this->status = $status ?? LicenseStatus::from('unknown');
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the string representation of the license
|
||||
*/
|
||||
public function __toString(): string
|
||||
{
|
||||
return $this->name();
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a license instance from a given value
|
||||
*/
|
||||
public static function from(
|
||||
Plugin $plugin,
|
||||
Closure|array|string|null $license
|
||||
): static {
|
||||
if ($license instanceof Closure) {
|
||||
return $license($plugin);
|
||||
}
|
||||
|
||||
if (is_array($license)) {
|
||||
return new static(
|
||||
plugin: $plugin,
|
||||
name: $license['name'] ?? '',
|
||||
link: $license['link'] ?? null,
|
||||
status: LicenseStatus::from($license['status'] ?? 'active')
|
||||
);
|
||||
}
|
||||
|
||||
if ($license === null || $license === '-') {
|
||||
return new static(
|
||||
plugin: $plugin,
|
||||
name: '-',
|
||||
status: LicenseStatus::from('unknown')
|
||||
);
|
||||
}
|
||||
|
||||
return new static(
|
||||
plugin: $plugin,
|
||||
name: $license,
|
||||
status: LicenseStatus::from('active')
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the license link. This can be the
|
||||
* license terms or a link to a shop to
|
||||
* purchase a license.
|
||||
*/
|
||||
public function link(): string|null
|
||||
{
|
||||
return $this->link;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the license name
|
||||
*/
|
||||
public function name(): string
|
||||
{
|
||||
return $this->name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the license status
|
||||
*/
|
||||
public function status(): LicenseStatus
|
||||
{
|
||||
return $this->status;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the license information as an array
|
||||
*/
|
||||
public function toArray(): array
|
||||
{
|
||||
return [
|
||||
'link' => $this->link(),
|
||||
'name' => $this->name(),
|
||||
'status' => $this->status()->toArray()
|
||||
];
|
||||
}
|
||||
}
|
||||
135
public/kirby/src/Plugin/LicenseStatus.php
Normal file
135
public/kirby/src/Plugin/LicenseStatus.php
Normal file
|
|
@ -0,0 +1,135 @@
|
|||
<?php
|
||||
|
||||
namespace Kirby\Plugin;
|
||||
|
||||
use Kirby\Cms\LicenseStatus as SystemLicenseStatus;
|
||||
use Stringable;
|
||||
|
||||
/**
|
||||
* Represents the license status of a plugin.
|
||||
* Used to display the status in the Panel system view
|
||||
*
|
||||
* @package Kirby Plugin
|
||||
* @author Bastian Allgeier <bastian@getkirby.com>
|
||||
* @link https://getkirby.com
|
||||
* @copyright Bastian Allgeier
|
||||
* @license https://getkirby.com/license
|
||||
* @since 5.0.0
|
||||
*/
|
||||
class LicenseStatus implements Stringable
|
||||
{
|
||||
public function __construct(
|
||||
protected string $value,
|
||||
protected string $icon,
|
||||
protected string $label,
|
||||
protected string|null $link = null,
|
||||
protected string|null $dialog = null,
|
||||
protected string|null $drawer = null,
|
||||
protected string|null $theme = null
|
||||
) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the status label
|
||||
*/
|
||||
public function __toString(): string
|
||||
{
|
||||
return $this->label();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the status dialog
|
||||
*/
|
||||
public function dialog(): string|null
|
||||
{
|
||||
return $this->dialog;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the status drawer
|
||||
*/
|
||||
public function drawer(): string|null
|
||||
{
|
||||
return $this->drawer;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a status by its name
|
||||
*/
|
||||
public static function from(LicenseStatus|string|array|null $status): static
|
||||
{
|
||||
if ($status instanceof LicenseStatus) {
|
||||
return $status;
|
||||
}
|
||||
|
||||
if (is_array($status) === true) {
|
||||
return new static(...$status);
|
||||
}
|
||||
|
||||
$status = SystemLicenseStatus::from($status ?? 'unknown');
|
||||
$status ??= SystemLicenseStatus::Unknown;
|
||||
|
||||
return new static(
|
||||
value: $status->value,
|
||||
icon: $status->icon(),
|
||||
label: $status->label(),
|
||||
theme: $status->theme()
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the status icon
|
||||
*/
|
||||
public function icon(): string
|
||||
{
|
||||
return $this->icon;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the status label
|
||||
*/
|
||||
public function label(): string
|
||||
{
|
||||
return $this->label;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the status link
|
||||
*/
|
||||
public function link(): string|null
|
||||
{
|
||||
return $this->link;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the theme
|
||||
*/
|
||||
public function theme(): string|null
|
||||
{
|
||||
return $this->theme;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the status information as an array
|
||||
*/
|
||||
public function toArray(): array
|
||||
{
|
||||
return [
|
||||
'dialog' => $this->dialog(),
|
||||
'drawer' => $this->drawer(),
|
||||
'icon' => $this->icon(),
|
||||
'label' => $this->label(),
|
||||
'link' => $this->link(),
|
||||
'theme' => $this->theme(),
|
||||
'value' => $this->value(),
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the status value
|
||||
*/
|
||||
public function value(): string
|
||||
{
|
||||
return $this->value;
|
||||
}
|
||||
}
|
||||
354
public/kirby/src/Plugin/Plugin.php
Normal file
354
public/kirby/src/Plugin/Plugin.php
Normal file
|
|
@ -0,0 +1,354 @@
|
|||
<?php
|
||||
|
||||
namespace Kirby\Plugin;
|
||||
|
||||
use Closure;
|
||||
use Composer\InstalledVersions;
|
||||
use Kirby\Cms\App;
|
||||
use Kirby\Cms\Helpers;
|
||||
use Kirby\Cms\System\UpdateStatus;
|
||||
use Kirby\Data\Data;
|
||||
use Kirby\Exception\InvalidArgumentException;
|
||||
use Kirby\Toolkit\A;
|
||||
use Kirby\Toolkit\Str;
|
||||
use Kirby\Toolkit\V;
|
||||
use Throwable;
|
||||
|
||||
/**
|
||||
* Represents a Plugin and handles parsing of
|
||||
* the composer.json. It also creates the prefix
|
||||
* and media url for the plugin.
|
||||
*
|
||||
* @package Kirby Plugin
|
||||
* @author Bastian Allgeier <bastian@getkirby.com>
|
||||
* @link https://getkirby.com
|
||||
* @copyright Bastian Allgeier
|
||||
* @license https://getkirby.com/license
|
||||
*/
|
||||
class Plugin
|
||||
{
|
||||
protected Assets $assets;
|
||||
protected License|Closure|array|string $license;
|
||||
protected UpdateStatus|null $updateStatus = null;
|
||||
|
||||
/**
|
||||
* @param string $name Plugin name within Kirby (`vendor/plugin`)
|
||||
* @param array $extends Associative array of plugin extensions
|
||||
*
|
||||
* @throws \Kirby\Exception\InvalidArgumentException If the plugin name has an invalid format
|
||||
*/
|
||||
public function __construct(
|
||||
protected string $name,
|
||||
protected array $extends = [],
|
||||
protected array $info = [],
|
||||
Closure|string|array|null $license = null,
|
||||
protected string|null $root = null,
|
||||
protected string|null $version = null,
|
||||
) {
|
||||
static::validateName($name);
|
||||
|
||||
// TODO: Remove in v7
|
||||
if ($root = $extends['root'] ?? null) {
|
||||
Helpers::deprecated('Plugin "' . $name . '": Passing the `root` inside the `extends` array has been deprecated. Pass it directly as named argument `root`.', 'plugin-extends-root');
|
||||
$this->root ??= $root;
|
||||
unset($this->extends['root']);
|
||||
}
|
||||
|
||||
$this->root ??= dirname(debug_backtrace()[0]['file']);
|
||||
|
||||
// TODO: Remove in v7
|
||||
if ($info = $extends['info'] ?? null) {
|
||||
Helpers::deprecated('Plugin "' . $name . '": Passing an `info` array inside the `extends` array has been deprecated. Pass the individual entries directly as named `info` argument.', 'plugin-extends-root');
|
||||
|
||||
if (empty($info) === false && is_array($info) === true) {
|
||||
$this->info = [...$info, ...$this->info];
|
||||
}
|
||||
|
||||
unset($this->extends['info']);
|
||||
}
|
||||
|
||||
// read composer.json and use as info fallback
|
||||
$info = Data::read($this->manifest(), fail: false);
|
||||
$this->info = [...$info, ...$this->info];
|
||||
$this->license = $license ?? $this->info['license'] ?? '-';
|
||||
}
|
||||
|
||||
/**
|
||||
* Allows access to any composer.json field by method call
|
||||
*/
|
||||
public function __call(string $key, array|null $arguments = null): mixed
|
||||
{
|
||||
return $this->info()[$key] ?? null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the plugin asset object for a specific asset
|
||||
*/
|
||||
public function asset(string $path): Asset|null
|
||||
{
|
||||
return $this->assets()->get($path);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the plugin assets collection
|
||||
*/
|
||||
public function assets(): Assets
|
||||
{
|
||||
return $this->assets ??= Assets::factory($this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the array with author information
|
||||
* from the composer.json file
|
||||
*/
|
||||
public function authors(): array
|
||||
{
|
||||
return $this->info()['authors'] ?? [];
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a comma-separated list with all author names
|
||||
*/
|
||||
public function authorsNames(): string
|
||||
{
|
||||
$names = [];
|
||||
|
||||
foreach ($this->authors() as $author) {
|
||||
$names[] = $author['name'] ?? null;
|
||||
}
|
||||
|
||||
return implode(', ', array_filter($names));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the associative array of extensions the plugin bundles
|
||||
*/
|
||||
public function extends(): array
|
||||
{
|
||||
return $this->extends;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the unique ID for the plugin
|
||||
* (alias for the plugin name)
|
||||
*/
|
||||
public function id(): string
|
||||
{
|
||||
return $this->name();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the info data (from composer.json)
|
||||
*/
|
||||
public function info(): array
|
||||
{
|
||||
return $this->info;
|
||||
}
|
||||
|
||||
/**
|
||||
* Current $kirby instance
|
||||
*/
|
||||
public function kirby(): App
|
||||
{
|
||||
return App::instance();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the link to the plugin homepage
|
||||
*/
|
||||
public function link(): string|null
|
||||
{
|
||||
$info = $this->info();
|
||||
$homepage = $info['homepage'] ?? null;
|
||||
$docs = $info['support']['docs'] ?? null;
|
||||
$source = $info['support']['source'] ?? null;
|
||||
|
||||
$link = $homepage ?? $docs ?? $source;
|
||||
|
||||
return V::url($link) ? $link : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the license object
|
||||
*/
|
||||
public function license(): License
|
||||
{
|
||||
// resolve license info from Closure, array or string
|
||||
return License::from(
|
||||
plugin: $this,
|
||||
license: $this->license
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the path to the plugin's composer.json
|
||||
*/
|
||||
public function manifest(): string
|
||||
{
|
||||
return $this->root() . '/composer.json';
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the root where plugin assets are copied to
|
||||
*/
|
||||
public function mediaRoot(): string
|
||||
{
|
||||
return $this->kirby()->root('media') . '/plugins/' . $this->name();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the base URL for plugin assets
|
||||
*/
|
||||
public function mediaUrl(): string
|
||||
{
|
||||
return $this->kirby()->url('media') . '/plugins/' . $this->name();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the plugin name (`vendor/plugin`)
|
||||
*/
|
||||
public function name(): string
|
||||
{
|
||||
return $this->name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a Kirby option value for this plugin
|
||||
*/
|
||||
public function option(string $key)
|
||||
{
|
||||
return $this->kirby()->option($this->prefix() . '.' . $key);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the option prefix (`vendor.plugin`)
|
||||
*/
|
||||
public function prefix(): string
|
||||
{
|
||||
return str_replace('/', '.', $this->name());
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the root where the plugin files are stored
|
||||
*/
|
||||
public function root(): string
|
||||
{
|
||||
return $this->root;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns all available plugin metadata
|
||||
*/
|
||||
public function toArray(): array
|
||||
{
|
||||
return [
|
||||
'authors' => $this->authors(),
|
||||
'description' => $this->description(),
|
||||
'name' => $this->name(),
|
||||
'license' => $this->license()->toArray(),
|
||||
'link' => $this->link(),
|
||||
'root' => $this->root(),
|
||||
'version' => $this->version()
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the update status object unless the
|
||||
* update check has been disabled for the plugin
|
||||
* @since 3.8.0
|
||||
*
|
||||
* @param array|null $data Custom override for the getkirby.com update data
|
||||
*/
|
||||
public function updateStatus(array|null $data = null): UpdateStatus|null
|
||||
{
|
||||
if ($this->updateStatus !== null) {
|
||||
return $this->updateStatus;
|
||||
}
|
||||
|
||||
$kirby = $this->kirby();
|
||||
$option = $kirby->option('updates.plugins');
|
||||
|
||||
// specific configuration per plugin
|
||||
if (is_array($option) === true) {
|
||||
// filter all option values by glob match
|
||||
$option = A::filter(
|
||||
$option,
|
||||
fn ($value, $key) => fnmatch($key, $this->name()) === true
|
||||
);
|
||||
|
||||
// sort the matches by key length (with longest key first)
|
||||
$keys = array_map('strlen', array_keys($option));
|
||||
array_multisort($keys, SORT_DESC, $option);
|
||||
|
||||
if ($option !== []) {
|
||||
// use the first and therefore longest key (= most specific match)
|
||||
$option = reset($option);
|
||||
} else {
|
||||
// fallback to the default option value
|
||||
$option = true;
|
||||
}
|
||||
}
|
||||
|
||||
$option ??= $kirby->option('updates') ?? true;
|
||||
|
||||
if ($option !== true) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return $this->updateStatus = new UpdateStatus($this, false, $data);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the name follows the required pattern
|
||||
* and throws an exception if not
|
||||
*
|
||||
* @throws \Kirby\Exception\InvalidArgumentException
|
||||
*/
|
||||
public static function validateName(string $name): void
|
||||
{
|
||||
if (preg_match('!^[a-z0-9-]+\/[a-z0-9-]+$!i', $name) !== 1) {
|
||||
throw new InvalidArgumentException(
|
||||
message: 'The plugin name must follow the format "a-z0-9-/a-z0-9-"'
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the normalized version number
|
||||
* from the composer.json file
|
||||
*/
|
||||
public function version(): string|null
|
||||
{
|
||||
$name = $this->info()['name'] ?? null;
|
||||
|
||||
try {
|
||||
// try to get version from "vendor/composer/installed.php",
|
||||
// this is the most reliable source for the version
|
||||
$version = InstalledVersions::getPrettyVersion($name);
|
||||
} catch (Throwable) {
|
||||
$version = null;
|
||||
}
|
||||
|
||||
// fallback to the version provided in the plugin's index.php: as named
|
||||
// argument, entry in the info array or from the composer.json file
|
||||
$version ??= $this->version ?? $this->info()['version'] ?? null;
|
||||
|
||||
if (
|
||||
is_string($version) !== true ||
|
||||
$version === '' ||
|
||||
Str::endsWith($version, '+no-version-set')
|
||||
) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// normalize the version number to be without leading `v`
|
||||
$version = ltrim($version, 'vV');
|
||||
|
||||
// ensure that the version number now starts with a digit
|
||||
if (preg_match('/^[0-9]/', $version) !== 1) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return $version;
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue