Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 26 additions & 4 deletions src/Cms/AppPlugins.php
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
use Kirby\Image\Image;
use Kirby\Plugin\License;
use Kirby\Plugin\Plugin;
use Kirby\Plugin\Autoloader;
use Kirby\Text\KirbyTag;
use Kirby\Toolkit\A;
use Kirby\Toolkit\Collection as ToolkitCollection;
Expand Down Expand Up @@ -871,18 +872,34 @@ public static function plugin(
string|null $root = null,
string|null $version = null,
Closure|string|array|null $license = null,
bool|string $autoloader = false
): Plugin|null {
if ($extends === null) {


if ($extends === null && $autoloader === false) {
return static::$plugins[$name] ?? null;
}

$root ??= $extends['root'] ?? dirname(debug_backtrace()[0]['file']);

if ($autoloader) {

//Allow to apply custom Autoloader
$autolader_class = is_bool($autoloader) ? Autoloader::class : $autoloader;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Question: What for would one use a custom autoloader class?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For example: In one of my cases i used it to extend the $this->extend() with data from a Class (Which is loading in the autoloader). So i made a custom Autoloader class and modified the toArray() method.
An other case could be, that you need to load snippets from another folder than snippets.


$extends = A::merge($autolader_class::load(
name: $name,
root: $root
), $extends ?? []);
}

$plugin = new Plugin(
name: $name,
name: $name,
extends: $extends,
info: $info,
info: $info,
license: $license,
// TODO: Remove fallback to $extends in v7
root: $root ?? $extends['root'] ?? dirname(debug_backtrace()[0]['file']),
root: $root,
version: $version
);

Expand Down Expand Up @@ -925,6 +942,11 @@ public function plugins(array|null $plugins = null): array
return static::$plugins;
}

public function allowedExtensionsKeys(): array
{
return array_keys($this->extensions);
}

Comment on lines +945 to +949
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We don't need to base the logic on the available extensions. It might seem like a good idea to make it dynamic based on this, but some verbosity will go a long way here for understanding and maintaining this (even with a bit more effort). Look at classes like Kirby\Cms\Core, Kirby\Cms\AppPlugins - writing code for each extension manually helps, even if that means we have to change the code in multiple classes when we add/remove an extension.

/**
* Loads all plugins from site/plugins
*
Expand Down
290 changes: 290 additions & 0 deletions src/Plugin/Autoloader.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,290 @@
<?php

namespace Kirby\Plugin;

/**
* Autoloader
*/

use Closure;
use Kirby\Filesystem\Dir;
use Kirby\Toolkit\A;
use Kirby\Data\Data;
use Kirby\Exception\Exception;
use Kirby\Exception\InvalidArgumentException;
use Kirby\Filesystem\F;
use Kirby\Toolkit\Str;
use Throwable;

class Autoloader
{

public array $data = [];

/**
* @param string $name Plugin name
* @param string $root The root path of the plugin
* @param array $data Predefined extension data to extend
* @return void|$this
*/
public function __construct(
public string $name,
public string $root
) {

//Load classes before everything else
$classfolder = $root . '/classes/';

if (Dir::exists($classfolder)) {
$this->loadClasses($classfolder);
}

$folders = [
'autoload' => 'loadAutoload',
'blueprints' => 'loadBlueprints',
'i18n' => 'loadTranslations',
'fields' => 'loadFields',
'sections' => 'loadSections',
'snippets' => 'loadSnippets',
'templates' => 'loadTemplates'
];

foreach (Dir::dirs($this->root) as $dir) {
if (array_key_exists($dir, $folders)) {
$method = $folders[$dir];
$this->$method($this->root . '/' . $dir . '/');
}
}
}

/**
* Autoload autoload
* @param string $root
* @return void
*/
public function loadAutoload(string $root): void
{
foreach (Dir::files($root) as $path) {

$key = F::name($path);
$file = $root . $path;
$this->data[$key] = Data::read($file);
};
}

/**
* Autoload blueprints
* @param string $root
* @return void
*/
public function loadBlueprints(string $root): void
{
foreach (Dir::index($root) as $path) {

$file = $root . $path;

//Skip folder and file/folder thats starts with '_'
if (F::exists($file) === false || Str::contains($path, '/_')) {
continue;
}

//Has no Subfolder
if (($dirname = F::dirname($path)) === '.') {
$key = F::name($path);
}

$key ??= $dirname . '/' . F::name($path);

$this->data['blueprints'][$key] = Data::read($file);
};
}

/**
* Load classes
* @param string $root
* @return void
*/
public function loadClasses(string $root): void
{

$classes = [];

foreach (Dir::index($root) as $path) {

$file = $root . $path;

//Skip folder and file/folder thats starts with '_'
if (F::exists($file) === false || Str::contains($path, '/_')) {
continue;
}

//Has no Subfolder
if (($dirname = F::dirname($path)) === '.') {
$key = F::name($path);
}

$key ??= $dirname . '/' . F::name($path);

$prefix = array_map('ucfirst', explode('/', $this->name));
$classname = A::merge($prefix, explode('/', $key));
$classes[implode('\\', $classname)] = $file;
};

F::loadClasses($classes);
}


/**
* Autoload translations
* @param string $root
* @return void
*/
public function loadTranslations(string $root): void
{
foreach (Dir::index($root) as $path) {

$file = $root . $path;

//Skip folder and file/folder thats starts with '_'
if (F::exists($file) === false || Str::contains($path, '/_')) {
continue;
}

//Has no Subfolder
if (($dirname = F::dirname($path)) === '.') {
$key = F::name($path);
}

$key ??= $dirname . '/' . F::name($path);

$this->data['translations'][$key] = Data::read($file);
};
}

/**
* Autoload fields
* @param string $root
* @return void
*/
public function loadFields(string $root): void
{
foreach (Dir::index($root) as $path) {

$file = $root . $path;

//Skip folder and file/folder thats starts with '_'
if (F::exists($file) === false || Str::contains($path, '/_')) {
continue;
}

//Has no Subfolder
if (($dirname = F::dirname($path)) === '.') {
$key = F::name($path);
}

$key ??= $dirname . '/' . F::name($path);

$this->data['fields'][$key] = Data::read($file);
};
}

/**
* Autoload sections
* @param string $root
* @return void
*/
public function loadSections(string $root): void
{
foreach (Dir::index($root) as $path) {

$file = $root . $path;

//Skip folder and file/folder thats starts with '_'
if (F::exists($file) === false || Str::contains($path, '/_')) {
continue;
}

//Has no Subfolder
if (($dirname = F::dirname($path)) === '.') {
$key = F::name($path);
}

$key ??= $dirname . '/' . F::name($path);

$this->data['sections'][$key] = Data::read($file);
};
}

/**
* Autoload snippets
* @param string $root
* @return void
*/
public function loadSnippets(string $root): void
{
foreach (Dir::index($root) as $path) {

$file = $root . $path;

//Skip folder and file/folder thats starts with '_'
if (F::exists($file) === false || Str::contains($path, '/_')) {
continue;
}

//Has no Subfolder
if (($dirname = F::dirname($path)) === '.') {
$key = F::name($path);
}

$key ??= $dirname . '/' . F::name($path);

$this->data['snippets'][$key] = $file;
};
}

/**
* Autoload templates
* @param string $root
* @return void
*/
public function loadTemplates(string $root): void
{
foreach (Dir::index($root) as $path) {

$file = $root . $path;

//Skip folder and file/folder thats starts with '_'
if (F::exists($file) === false || Str::contains($path, '/_')) {
continue;
}

//Has no Subfolder
if (($dirname = F::dirname($path)) === '.') {
$key = F::name($path);
}

$key ??= $dirname . '/' . F::name($path);

$this->data['templates'][$key] = $file;
};
}

/**
* Run autoloader and return the results
* @param mixed ...$params
* @return array
*/
public static function load(...$params): array
{
$self = new self(...$params);
return $self->toArray();
}

/**
* Returns the autoloaded data
* @return array */
public function toArray(): array
{
return $this->data;
}
}
1 change: 1 addition & 0 deletions src/Plugin/Plugin.php
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,7 @@ public function __construct(
$info = Data::read($this->manifest(), fail: false);
$this->info = [...$info, ...$this->info];
$this->license = $license ?? $this->info['license'] ?? '-';

}

/**
Expand Down
3 changes: 3 additions & 0 deletions vendor/composer/autoload_classmap.php
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,7 @@
'Kirby\\Cms\\HasChildren' => $baseDir . '/src/Cms/HasChildren.php',
'Kirby\\Cms\\HasFiles' => $baseDir . '/src/Cms/HasFiles.php',
'Kirby\\Cms\\HasMethods' => $baseDir . '/src/Cms/HasMethods.php',
'Kirby\\Cms\\HasModels' => $baseDir . '/src/Cms/HasModels.php',
'Kirby\\Cms\\HasSiblings' => $baseDir . '/src/Cms/HasSiblings.php',
'Kirby\\Cms\\Helpers' => $baseDir . '/src/Cms/Helpers.php',
'Kirby\\Cms\\Html' => $baseDir . '/src/Cms/Html.php',
Expand Down Expand Up @@ -205,6 +206,7 @@
'Kirby\\Form\\FieldClass' => $baseDir . '/src/Form/FieldClass.php',
'Kirby\\Form\\Field\\BlocksField' => $baseDir . '/src/Form/Field/BlocksField.php',
'Kirby\\Form\\Field\\EntriesField' => $baseDir . '/src/Form/Field/EntriesField.php',
'Kirby\\Form\\Field\\ExceptionField' => $baseDir . '/src/Form/Field/ExceptionField.php',
'Kirby\\Form\\Field\\LayoutField' => $baseDir . '/src/Form/Field/LayoutField.php',
'Kirby\\Form\\Fields' => $baseDir . '/src/Form/Fields.php',
'Kirby\\Form\\Form' => $baseDir . '/src/Form/Form.php',
Expand Down Expand Up @@ -314,6 +316,7 @@
'Kirby\\Parsley\\Schema\\Plain' => $baseDir . '/src/Parsley/Schema/Plain.php',
'Kirby\\Plugin\\Asset' => $baseDir . '/src/Plugin/Asset.php',
'Kirby\\Plugin\\Assets' => $baseDir . '/src/Plugin/Assets.php',
'Kirby\\Plugin\\Autoloader' => $baseDir . '/src/Plugin/Autoloader.php',
'Kirby\\Plugin\\License' => $baseDir . '/src/Plugin/License.php',
'Kirby\\Plugin\\LicenseStatus' => $baseDir . '/src/Plugin/LicenseStatus.php',
'Kirby\\Plugin\\Plugin' => $baseDir . '/src/Plugin/Plugin.php',
Expand Down
Loading
Loading