Release 2.7.0 (#4506)
* added api URL for simpler integration * allow to request password change upon next login * make ModifiedAt timesheet independent * improved plugin api * replace kernel calls with AutoconfigureTag and TaggedIterator attributes * new translation keys (e.g. for days) * support setting min and max date on date and daterange pickers
This commit is contained in:
@@ -11,42 +11,38 @@ namespace App\Plugin;
|
||||
|
||||
final class Plugin
|
||||
{
|
||||
private string $id;
|
||||
private string $path;
|
||||
private ?PluginMetadata $metadata = null;
|
||||
|
||||
public function __construct(PluginInterface $bundle)
|
||||
public function __construct(private readonly PluginInterface $bundle)
|
||||
{
|
||||
$this->id = $bundle->getName();
|
||||
$this->path = $bundle->getPath();
|
||||
}
|
||||
|
||||
public function getMetadata(): ?PluginMetadata
|
||||
public function getMetadata(): PluginMetadata
|
||||
{
|
||||
if ($this->metadata === null) {
|
||||
$this->metadata = new PluginMetadata($this->getPath());
|
||||
}
|
||||
|
||||
return $this->metadata;
|
||||
}
|
||||
|
||||
public function setMetadata(PluginMetadata $metadata): void
|
||||
{
|
||||
$this->metadata = $metadata;
|
||||
}
|
||||
|
||||
public function getPath(): string
|
||||
{
|
||||
return $this->path;
|
||||
return $this->bundle->getPath();
|
||||
}
|
||||
|
||||
public function getName(): string
|
||||
{
|
||||
if ($this->metadata !== null && $this->metadata->getName() !== null) {
|
||||
return $this->metadata->getName();
|
||||
$meta = $this->getMetadata();
|
||||
if ($meta->getName() !== null) {
|
||||
return $meta->getName();
|
||||
}
|
||||
|
||||
return $this->id;
|
||||
return $this->getId();
|
||||
}
|
||||
|
||||
public function getId(): string
|
||||
{
|
||||
return $this->id;
|
||||
return $this->bundle->getName();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,6 +9,9 @@
|
||||
|
||||
namespace App\Plugin;
|
||||
|
||||
use Symfony\Component\DependencyInjection\Attribute\AutoconfigureTag;
|
||||
|
||||
#[AutoconfigureTag]
|
||||
interface PluginInterface
|
||||
{
|
||||
public function getName(): string;
|
||||
|
||||
@@ -9,23 +9,23 @@
|
||||
|
||||
namespace App\Plugin;
|
||||
|
||||
use Symfony\Component\DependencyInjection\Attribute\TaggedIterator;
|
||||
|
||||
final class PluginManager
|
||||
{
|
||||
/**
|
||||
* @var array<Plugin>|null
|
||||
*/
|
||||
private ?array $plugins = null;
|
||||
/**
|
||||
* @var iterable<PluginInterface>
|
||||
*/
|
||||
private iterable $bundles;
|
||||
|
||||
/**
|
||||
* @param iterable<PluginInterface> $plugins
|
||||
* @param iterable<PluginInterface> $bundles
|
||||
*/
|
||||
public function __construct(iterable $plugins)
|
||||
public function __construct(
|
||||
#[TaggedIterator(PluginInterface::class)]
|
||||
private readonly iterable $bundles
|
||||
)
|
||||
{
|
||||
$this->bundles = $plugins;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -46,29 +46,27 @@ final class PluginManager
|
||||
return $this->plugins;
|
||||
}
|
||||
|
||||
public function hasPlugin(string $name): bool
|
||||
{
|
||||
foreach ($this->bundles as $plugin) {
|
||||
if ($plugin->getName() === $name) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public function getPlugin(string $name): ?Plugin
|
||||
{
|
||||
$plugins = $this->getPlugins();
|
||||
|
||||
foreach ($plugins as $plugin) {
|
||||
if ($plugin->getName() === $name) {
|
||||
if ($plugin->getId() === $name) {
|
||||
return $plugin;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Call this method and pass a plugin, to set its metadata.
|
||||
* This is not pre-filled by default, as it would mean to parse several composer.json on each request.
|
||||
*
|
||||
* @param Plugin $plugin
|
||||
* @throws \Exception
|
||||
*/
|
||||
public function loadMetadata(Plugin $plugin): void
|
||||
{
|
||||
$meta = PluginMetadata::loadFromComposer($plugin->getPath());
|
||||
$plugin->setMetadata($meta);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,11 +20,9 @@ class PluginMetadata
|
||||
private ?string $name = null;
|
||||
|
||||
/**
|
||||
* @param string $path
|
||||
* @return PluginMetadata
|
||||
* @throws \Exception
|
||||
*/
|
||||
public static function loadFromComposer(string $path): PluginMetadata
|
||||
public function __construct(string $path)
|
||||
{
|
||||
if (!is_dir($path) || !is_readable($path)) {
|
||||
throw new \Exception(sprintf('Bundle directory "%s" cannot be accessed.', $path));
|
||||
@@ -59,16 +57,13 @@ class PluginMetadata
|
||||
throw new \Exception(sprintf('Bundle "%s" defines an invalid Kimai minimum version in extra.kimai.require. Please provide an integer as in Constants::VERSION_ID.', $pluginName));
|
||||
}
|
||||
|
||||
$meta = new self();
|
||||
$meta->description = $json['description'] ?? '';
|
||||
$meta->homepage = $json['homepage'] ?? Constants::HOMEPAGE . '/store/';
|
||||
$meta->name = $json['extra']['kimai']['name'];
|
||||
$meta->kimaiVersion = $json['extra']['kimai']['require'];
|
||||
$this->description = $json['description'] ?? '';
|
||||
$this->homepage = $json['homepage'] ?? Constants::HOMEPAGE . '/store/';
|
||||
$this->name = $json['extra']['kimai']['name'];
|
||||
$this->kimaiVersion = $json['extra']['kimai']['require'];
|
||||
|
||||
// the version field is required if we use composer to install a plugin via var/packages/
|
||||
$meta->version = $json['extra']['kimai']['version'] ?? ($json['version'] ?? 'unknown');
|
||||
|
||||
return $meta;
|
||||
$this->version = $json['extra']['kimai']['version'] ?? ($json['version'] ?? 'unknown');
|
||||
}
|
||||
|
||||
public function getDescription(): ?string
|
||||
|
||||
Reference in New Issue
Block a user