- Added a file input for PDF uploads with validation for file type and size. - Implemented file size formatting and user feedback for selected files. - Created upload and cancel methods with placeholder for future API integration. feat: Create PaymentForm.vue for handling payments - Developed a form for entering payment details including date, amount, method, and notes. - Integrated currency formatting and dropdown for payment methods. - Implemented save and cancel actions with API call for saving payment data. docs: Add documentation for dynamic plugin menus and permissions - Provided guidelines for defining menu items and permissions in plugins. - Explained the process for synchronizing permissions and integrating menus in the frontend. - Included examples and best practices for plugin development. feat: Add database migrations for invoices, invoice items, and payments - Created migration scripts to define the database schema for invoices, invoice items, and payments. - Established foreign key relationships between invoices and related entities. feat: Implement command for synchronizing plugin permissions - Developed a console command to synchronize plugin permissions with the database. - Added options for dry-run and force synchronization for unlicensed modules. feat: Create API controller for plugin menu items - Implemented API endpoints to retrieve plugin menu items in both flat and grouped formats. - Ensured access control with role-based permissions for API access. feat: Develop service for managing plugin menu items - Created a service to collect and manage menu items from installed plugins. - Implemented methods for retrieving flat and grouped menu items for frontend use. feat: Add service for synchronizing plugin permissions - Developed a service to handle the synchronization of plugin permissions with the database. - Included logic for creating and updating permission modules based on plugin definitions.
11 KiB
Plugin-Menüs und Permissions
Anleitung zur dynamischen Registrierung von Menü-Items und Permissions durch Plugins.
Übersicht
Das Plugin-System unterstützt jetzt:
✅ Dynamische Menü-Items - Plugins können eigene Menüpunkte hinzufügen ✅ Automatische Permission-Synchronisation - Modul-Permissions werden automatisch in der DB angelegt ✅ Permission-basierte Sichtbarkeit - Menüpunkte erscheinen nur für berechtigte User ✅ Gruppierung - Plugin-Menüs können gruppiert werden
1. Menü-Items im Plugin definieren
In deiner Plugin-Klasse:
public function getMenuItems(): array
{
return [
[
'label' => 'Rechnungen', // Menü-Titel
'icon' => 'pi-file-pdf', // PrimeIcons Icon (ohne pi pi-fw prefix)
'group' => 'Finanzen', // Gruppierung im Menü
'items' => [
[
'label' => 'Alle Rechnungen',
'icon' => 'pi-list',
'to' => '/billing/invoices', // Vue Router path
'permission' => 'billing.view' // Optional: Permission-Check
],
[
'label' => 'Neue Rechnung',
'icon' => 'pi-plus',
'to' => '/billing/invoices/create',
'permission' => 'billing.create'
],
[
'separator' => true // Optional: Trennlinie
],
[
'label' => 'Einstellungen',
'icon' => 'pi-cog',
'to' => '/billing/settings',
'permission' => 'billing.manage'
]
]
]
];
}
Menü-Item Optionen:
| Feld | Typ | Required | Beschreibung |
|---|---|---|---|
label |
string | ✅ | Anzeigename des Menüpunkts |
icon |
string | ❌ | PrimeIcons Icon (ohne pi pi-fw prefix) |
to |
string | ❌ | Vue Router path |
url |
string | ❌ | Externe URL (alternativ zu to) |
items |
array | ❌ | Sub-Menüpunkte |
permission |
string | ❌ | Permission-String für Sichtbarkeits-Check |
group |
string | ❌ | Gruppierung im Hauptmenü |
separator |
bool | ❌ | Trennlinie (nur in Sub-Items) |
2. Permissions definieren
In deiner Plugin-Klasse:
public function getPermissionModules(): array
{
return ['billing', 'invoicing'];
}
Das System erstellt automatisch folgende Permissions:
billing.viewbilling.createbilling.editbilling.deletebilling.exportbilling.manage
Permission-Synchronisation durchführen:
# Alle Plugins synchronisieren
php bin/console app:plugin:sync-permissions
# Nur ein bestimmtes Plugin
php bin/console app:plugin:sync-permissions billing
# Dry-Run (zeigt nur was passieren würde)
php bin/console app:plugin:sync-permissions --dry-run
Output:
Plugin Permission-Module Synchronisation
========================================
Synchronisiere alle Plugins...
------------------------------
Aktion Anzahl
Neu erstellt 2
Aktualisiert 0
Übersprungen 5
3. Frontend Integration
API-Endpoints:
GET /api/plugin-menu
Gibt alle Plugin-Menü-Items als flache Liste zurück.
Response:
{
"success": true,
"data": [
{
"label": "Alle Rechnungen",
"icon": "pi-list",
"to": "/billing/invoices",
"permission": "billing.view",
"source": "billing"
}
],
"count": 1
}
GET /api/plugin-menu/grouped
Gibt gruppierte Plugin-Menü-Items zurück.
Response:
{
"success": true,
"data": {
"Finanzen": [
{
"label": "Rechnungen",
"icon": "pi-file-pdf",
"items": [...]
}
]
},
"groups": ["Finanzen"]
}
AppMenu.vue
Das Menü lädt automatisch Plugin-Menüs beim Mount:
<script setup>
import { ref, onMounted } from 'vue';
const model = ref([...coreMenu]);
const loadPluginMenus = async () => {
const response = await fetch('/api/plugin-menu/grouped');
const data = await response.json();
// Plugin-Menüs werden automatisch hinzugefügt
// Permission-Checks werden automatisch durchgeführt
};
onMounted(() => {
loadPluginMenus();
});
</script>
4. Permission-Checks im Frontend
Mit Composition API:
<script setup>
import { useAuthStore } from '@/stores/auth';
const authStore = useAuthStore();
// Permission prüfen
const canViewInvoices = authStore.hasPermission('billing.view');
</script>
<template>
<Button v-if="canViewInvoices" label="Rechnung anzeigen" />
</template>
Im Template:
<template>
<div v-if="authStore.hasPermission('billing.create')">
<Button label="Neue Rechnung" @click="createInvoice" />
</div>
</template>
5. Beispiel: Vollständiges Plugin
BillingModulePlugin.php
<?php
namespace MyCRM\BillingModule;
use App\Plugin\LicenseValidatorInterface;
use App\Plugin\ModulePluginInterface;
class BillingModulePlugin implements ModulePluginInterface
{
public function __construct(
private readonly LicenseValidatorInterface $licenseValidator
) {}
public function getIdentifier(): string
{
return 'billing';
}
public function getDisplayName(): string
{
return 'Rechnungsmodul';
}
public function getVersion(): string
{
return '1.0.0';
}
public function getDescription(): string
{
return 'Verwaltung von Rechnungen, Angeboten und Zahlungen';
}
public function isLicensed(): bool
{
return $this->licenseValidator->validate('billing')['valid'];
}
public function getLicenseInfo(): array
{
return $this->licenseValidator->validate('billing');
}
public function boot(): void
{
if (!$this->isLicensed()) {
throw new \RuntimeException('Billing Module nicht lizenziert');
}
// Services, Routes, etc. registrieren
}
public function getPermissionModules(): array
{
return ['billing', 'invoicing', 'payments'];
}
public function getMenuItems(): array
{
return [
[
'label' => 'Rechnungen',
'icon' => 'pi-file-pdf',
'group' => 'Finanzen',
'items' => [
[
'label' => 'Dashboard',
'icon' => 'pi-chart-line',
'to' => '/billing/dashboard',
'permission' => 'billing.view'
],
[
'label' => 'Alle Rechnungen',
'icon' => 'pi-list',
'to' => '/billing/invoices',
'permission' => 'billing.view'
],
[
'label' => 'Neue Rechnung',
'icon' => 'pi-plus',
'to' => '/billing/invoices/create',
'permission' => 'billing.create'
],
[
'separator' => true
],
[
'label' => 'Zahlungen',
'icon' => 'pi-money-bill',
'to' => '/billing/payments',
'permission' => 'payments.view'
],
[
'label' => 'Einstellungen',
'icon' => 'pi-cog',
'to' => '/billing/settings',
'permission' => 'billing.manage'
]
]
]
];
}
public function canInstall(): array
{
$errors = [];
if (PHP_VERSION_ID < 80200) {
$errors[] = 'PHP 8.2+ erforderlich';
}
return [
'success' => empty($errors),
'errors' => $errors
];
}
}
6. Workflow: Neues Plugin mit Menüs
Schritt 1: Plugin erstellen
cd ../mycrm-billing-module
composer init
# Name: mycrm/billing-module
Schritt 2: Plugin-Klasse implementieren
Siehe Beispiel oben - implementiere getMenuItems() und getPermissionModules().
Schritt 3: In myCRM installieren
cd ../myCRM
composer config repositories.mycrm-billing-module path ../mycrm-billing-module
composer require mycrm/billing-module:@dev
Schritt 4: Permissions synchronisieren
php bin/console app:plugin:sync-permissions billing
Output:
Neu erstellt: 3 (billing, invoicing, payments)
Schritt 5: Cache leeren
php bin/console cache:clear
Schritt 6: Lizenz aktivieren
php bin/console app:module:license billing YOUR_GITEA_TOKEN
Schritt 7: Testen
- Frontend öffnen
- Plugin-Menü erscheint unter "Finanzen"
- Menüpunkte sind nur sichtbar mit Berechtigung
7. Debugging
Menü-Items überprüfen:
curl http://localhost:8000/api/plugin-menu | jq
Permissions in DB überprüfen:
SELECT * FROM modules WHERE code IN ('billing', 'invoicing', 'payments');
Plugin-Status:
php bin/console app:module:list
Logs:
tail -f var/log/dev.log | grep -E "(Plugin|Menu|Permission)"
8. Best Practices
✅ DO's:
- Gruppiere verwandte Menüs - Nutze
groupfür bessere Organisation - Permission-Checks - Definiere
permissionfür alle sensiblen Menüpunkte - Icons verwenden - Macht das Menü übersichtlicher
- Synchronisiere nach Installation -
app:plugin:sync-permissionsnach jedem Plugin-Update
❌ DON'Ts:
- Keine Core-Gruppen überschreiben - "Home", "CRM", "Administration" sind reserviert
- Keine tiefen Verschachtelungen - Max. 2 Ebenen (Gruppe → Items)
- Keine externen URLs ohne Warnung - User erwarten interne Navigation
9. Troubleshooting
Problem: Menü erscheint nicht
Lösung:
# Cache leeren
php bin/console cache:clear
# Plugin-Status prüfen
php bin/console app:module:list
# API testen
curl http://localhost:8000/api/plugin-menu/grouped
# Browser-Console überprüfen
Problem: Permissions fehlen
Lösung:
# Permissions synchronisieren
php bin/console app:plugin:sync-permissions
# DB überprüfen
SELECT * FROM modules WHERE code = 'billing';
# Rolle zuweisen
# In der Rollenverwaltung das neue Modul auswählen
Problem: Permission-Checks funktionieren nicht
Lösung:
- Prüfe ob User die Rolle hat
- Prüfe ob Rolle die Permission hat
- Prüfe
authStore.hasPermission()Implementierung
10. Migration bestehender Plugins
Wenn du bereits Plugins hast, füge einfach getMenuItems() hinzu:
// Altes Plugin
class MyPlugin implements ModulePluginInterface {
// ... bestehende Methoden ...
}
// Neu: Füge hinzu
class MyPlugin implements ModulePluginInterface {
// ... bestehende Methoden ...
public function getMenuItems(): array
{
return [
// Deine Menüs hier
];
}
}
Dann:
composer dump-autoload
php bin/console cache:clear
Support
Bei Fragen siehe:
PLUGIN_SYSTEM.md- Allgemeine Plugin-ArchitekturGITEA_LICENSE_SYSTEM.md- Lizenzierungdocs/PERMISSIONS.md- Permission-System