Live Demo: Teste alle Plugins für OXID eShop, Shopware und osTicket von Markus Michalski live — ohne Installation, ohne Risiko. demo.markus-michalski.net
Das Subticket Manager Plugin verwandelt osTickets versteckte Parent/Child-Ticket-Infrastruktur in ein voll funktionsfähiges, benutzerfreundliches Feature. Während osTicket die Datenbankstruktur (ticket_pid-Feld) und API-Methoden (isChild(), getPid()) bereitstellt, fehlt jegliche Benutzeroberfläche oder Workflow-Automatisierung.
Dieses Plugin bietet eine komplette Lösung für die Verwaltung hierarchischer Ticket-Beziehungen mit visuellen Indikatoren, Workflow-Automatisierung und einer intuitiven Oberfläche zum Erstellen und Verwalten von Subtickets.
Warum dieses Plugin unverzichtbar ist:
osTicket hat bereits die technische Grundlage für Parent/Child-Tickets im Kernsystem eingebaut, bietet aber:
Dieses Plugin macht osTickets versteckte Parent/Child-Infrastruktur tatsächlich nutzbar für den täglichen Support-Betrieb.
ticket_pid), keine Änderungen an Core-Dateien| Anforderung | Version | Hinweise |
|---|---|---|
| osTicket | 1.18.x | Plugin nutzt osTickets native ticket_pid-Infrastruktur |
| PHP | 7.4+ | Empfohlen: PHP 8.1+ für beste Performance |
| jQuery | Beliebig | In osTicket standardmäßig enthalten |
| Datenbank | MariaDB 10.3+ oder MySQL 5.7+ | Plugin erstellt zusätzliche Metadaten-Tabellen |
subticket-manager-Ordner nach /include/plugins/ auf deinem osTicket-Server hochFinaler Pfad: /pfad/zu/osticket/include/plugins/subticket-manager/
cd /pfad/zu/osticket/include/plugins
git clone https://github.com/markus-michalski/osticket-subticket-manager.git
scp/subtickets.php, scp/apps.php)scp/ajax-subticket.php)Admin-Interface prüfen:
Ticket-Ansicht prüfen:
Queue-Indikatoren prüfen:
Das Plugin benötigt keine Konfiguration - es funktioniert sofort nach Aktivierung mit osTickets nativer Parent/Child-Infrastruktur.
Alle Features werden automatisch beim Plugin-Start aktiviert:
Optionale Einstellungen:
SUBTICKET_DEBUG = true in class.SubticketPlugin.php (Zeile 8) für detailliertes Logging nach /tmp/subticket-debug.logVom Parent-Ticket aus:
tickets.php?a=open&subticket_parent=15)model.created Signal-Handler)Option 1: Vom Child-Ticket aus
Option 2: Vom Parent-Ticket aus
Vom Child-Ticket aus:
ticket_pid auf NULL gesetzt)Vom Parent-Ticket aus:
Queue-Listen:
queue-indicator.js) über AJAX-Endpoint hinzugefügtTicket-Ansicht:
Parent Ticket (3 Sub-Tickets)
background: #e8f4f8; border-left: 4px solid #1e90ff)Navigiere zu: Anwendungen → Subticket Hierarchies (scp/subtickets.php)
Features:
Das Plugin bietet eigenständige AJAX-Endpunkte für Frontend-Operationen:
Basis-URL: /scp/ajax-subticket.php
POST /scp/ajax-subticket.php?action=link
Content-Type: application/x-www-form-urlencoded
child_id=123&parent_number=181752&__CSRFToken__=abc123
Antwort:
{
"success": true,
"message": "Ticket linked successfully"
}
POST /scp/ajax-subticket.php?action=unlink
Content-Type: application/x-www-form-urlencoded
child_id=123&__CSRFToken__=abc123
Antwort:
{
"success": true,
"message": "Ticket unlinked successfully"
}
GET /scp/ajax-subticket.php?action=batch_parent_status&ticket_ids=15,16,17
Antwort:
{
"15": {"isParent": true, "childCount": 3},
"16": {"isParent": false, "childCount": 0},
"17": {"isParent": true, "childCount": 1}
}
Symptome:
Prüfen:
// DevTools öffnen (F12) → Console-Tab
// Nach Fehlern von queue-indicator.js suchen
// In Browser-Konsole:
typeof jQuery // Sollte "function" zurückgeben
// In Browser-Konsole:
SubticketPanel.debug = true
curl "http://osticket.local/scp/ajax-subticket.php?action=batch_parent_status&ticket_ids=15"
Symptome:
ticket_pid NICHT NULL istPrüfen:
Datenbank-Beziehung verifizieren:
SELECT ticket_id, number, ticket_pid, status_id
FROM ost_ticket
WHERE ticket_id = 123;
Prüfen, ob Parent-Ticket existiert:
SELECT * FROM ost_ticket WHERE ticket_id = (
SELECT ticket_pid FROM ost_ticket WHERE ticket_id = 123
);
Trennen und erneut verknüpfen:
Join-Query im Plugin-Code prüfen:
/tmp/subticket-debug.log öffnen (wenn Debug-Modus aktiviert)Symptome:
Prüfen:
Plugin ist aktiviert:
Browser-Cache leeren (könnte durch altes CSS verborgen sein)
Prüfen, ob Panel collapsed ist:
<div class="subticket-panel section-break"> suchen (F12 → Elements)Verifizieren, dass du im Staff-Interface bist:
Signal-Registrierung prüfen:
define('SUBTICKET_DEBUG', true);/tmp/subticket-debug.log prüfen auf:Signal registered: object.view for ticket view integration
onTicketView() called: Object: Ticket
Symptome:
Prüfen:
Du hast Berechtigung, Tickets zu erstellen:
Parent-Ticket ist nicht geschlossen:
tickets.php?a=open&subticket_parent=X)Apache Error Log prüfen:
tail -f /var/log/apache2/error.log
Session-Storage-Problem:
$_SESSION['subticket_parent'] nach Button-Klick gesetzt ist/tmp/subticket-debug.log prüfen:Stored subticket_parent in session: 15
Auto-linking ticket: Child: 456, Parent: 15
Symptome:
Lösung:
Falls Problem weiterhin besteht:
include/plugins/ auf Duplikate)Symptome:
Erklärung:
Das Plugin verhindert zirkuläre Abhängigkeiten, um die Baumintegrität zu wahren. Beispiel:
Lösung:
Symptome:
Prüfen:
Bestehende Tabellen prüfen:
SHOW TABLES LIKE 'ost_ticket_hierarchy_metadata';
SHOW TABLES LIKE 'ost_ticket_progress';
Bestehende Spalten prüfen:
SHOW COLUMNS FROM ost_ticket LIKE 'version';
Plugin behandelt Duplikate bereits - Bei fehlgeschlagener Aktivierung Apache Error Log auf spezifische SQL-Fehler prüfen
Manuelles Cleanup (falls nötig):
-- VORSICHT: Nur bei Neuinstallation ausführen!
DROP TABLE IF EXISTS ost_ticket_hierarchy_metadata;
DROP TABLE IF EXISTS ost_ticket_progress;
ALTER TABLE ost_ticket DROP COLUMN IF EXISTS version;
Plugin-Struktur:
subticket-manager/
├── plugin.php # Plugin-Metadaten
├── class.SubticketPlugin.php # Haupt-Plugin-Klasse
├── config.php # Plugin-Konfigurationsklasse
├── queue-decoration.php # Queue-SQL-Erweiterung (ParentTicketDecoration)
├── ajax/
│ └── SubticketAjaxAPI.php # AJAX-Endpunkt-Handler (Legacy)
├── scp-files/
│ ├── subtickets.php # Admin-Interface-Seite (deployed nach scp/)
│ ├── apps.php # Anwendungs-Übersichtsseite
│ └── ajax-subticket.php # Eigenständiger AJAX-Handler
├── js/
│ ├── subticket-panel.js # Frontend-Panel-Interaktionen
│ └── queue-indicator.js # Queue-Listen Parent-Indikatoren
├── services/
│ ├── SubticketService.php # Business-Logic-Layer
│ └── SubticketCreator.php # Ticket-Erstellungs-Service
├── repositories/
│ └── SubticketRelationRepository.php # Datenbank-Zugriffs-Layer
├── validation/
│ └── SubticketValidator.php # Input-Validierung
├── cache/
│ └── SubticketCacheManager.php # Performance-Optimierung
├── events/
│ └── SubticketEventHandler.php # Signal-Handler (Auto-Close, etc.)
└── tests/
└── Unit/ # PHPUnit-Tests
Signal-Hooks:
| Signal | Handler | Zweck |
|---|---|---|
object.view |
onTicketView() |
Panel-HTML in Ticket-Ansicht einfügen |
model.created |
onTicketCreated() |
Neu erstellte Subtickets automatisch verknüpfen |
model.updated |
onTicketStatusChanged() |
Auto-Close-Workflow auslösen (Phase 4) |
ajax.scp |
registerAjaxRoutes() |
AJAX-Endpunkte registrieren (Legacy, ungenutzt) |
Datenbank-Schema:
-- Zusätzliche vom Plugin erstellte Tabellen
CREATE TABLE ost_ticket_hierarchy_metadata (
ticket_id int(11) unsigned PRIMARY KEY,
auto_close_enabled tinyint(1) DEFAULT 1,
inherit_settings text,
dependency_type enum('blocks','depends_on','relates_to') DEFAULT 'relates_to',
max_children int(11) DEFAULT 50,
created timestamp DEFAULT CURRENT_TIMESTAMP,
updated timestamp DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
FOREIGN KEY (ticket_id) REFERENCES ost_ticket(ticket_id) ON DELETE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
CREATE TABLE ost_ticket_progress (
parent_id int(11) unsigned PRIMARY KEY,
total_children int(11) DEFAULT 0,
completed_children int(11) DEFAULT 0,
in_progress_children int(11) DEFAULT 0,
pending_children int(11) DEFAULT 0,
last_calculated timestamp DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
FOREIGN KEY (parent_id) REFERENCES ost_ticket(ticket_id) ON DELETE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
-- Zu ost_ticket hinzugefügte Indizes
CREATE INDEX idx_ticket_pid ON ost_ticket(ticket_pid);
CREATE INDEX idx_ticket_hierarchy ON ost_ticket(ticket_id, ticket_pid, status_id);
-- Zu ost_ticket hinzugefügte Spalte
ALTER TABLE ost_ticket ADD COLUMN version int(11) DEFAULT 0;
Input-Validierung:
db_input() für SQL-Escaping verwendet (osTicket-Standard)Verhinderung zirkulärer Abhängigkeiten:
isDescendant()-Methode prüft Abstammung bis 10 EbenenVerhinderung von Self-Linking:
Berechtigungs-Prüfungen:
Single Query für Children:
getChildren() nutzt JOIN, um Subject und Status in einer Abfrage zu holenQueue-Indikator-Caching:
queue-indicator.js bündelt Parent-Status-ChecksAuto-Deploy-Versions-Prüfung:
.subticket-deployed-version-DateiDatenbank-Indizes:
idx_ticket_pid beschleunigt Child-Lookupsidx_ticket_hierarchy optimiert Parent-Child-QueriesF: Muss ich osTicket Core-Dateien modifizieren?
A: Nein! Das Plugin nutzt osTickets native ticket_pid-Infrastruktur und Signal-System. Alle Features funktionieren ohne Berührung von Core-Dateien.
F: Funktioniert das mit meinem benutzerdefinierten osTicket-Theme?
A: Ja, das Plugin nutzt osTickets Standard-CSS-Klassen und -Struktur. Visuelle Indikatoren und Panels passen sich automatisch an dein Theme an.
F: Kann ich osTicket upgraden, ohne das Plugin zu brechen?
A: Ja, solange osTicket das ticket_pid-Feld und Signal-System beibehält (diese sind Core-Features). Das Plugin ist gegen osTicket 1.18.x getestet.
F: Wie deinstalliere ich das Plugin?
A: Admin Panel → Plugins → Subticket Manager → Löschen. Das Plugin wird:
scp/subtickets.php, scp/ajax-subticket.php, scp/apps.php)ticket_pid)F: Was ist die maximale Hierarchie-Tiefe?
A: Das Plugin unterstützt bis zu 10 Verschachtelungsebenen (konfigurierbar in isDescendant()-Methode). Dies verhindert Endlosschleifen und wahrt die Performance.
F: Kann ein Ticket mehrere Parents haben?
A: Nein. osTickets ticket_pid-Feld unterstützt nur einen Parent pro Ticket. Dies entspricht dem Baum-Struktur-Design.
F: Kann ich Tickets in Bulk verknüpfen?
A: Ja, nutze die Subticket Hierarchies Admin-Seite (Anwendungen → Subticket Hierarchies) für Batch-Operationen.
F: Was passiert, wenn ich ein Parent-Ticket lösche?
A: Standardmäßig bleiben Child-Tickets erhalten, aber ihr ticket_pid wird auf NULL gesetzt (getrennt). Falls du Foreign-Key-Constraints mit ON DELETE CASCADE hast, würden auch Children gelöscht.
F: Funktioniert Auto-Close sofort?
A: Auto-Close ist ein Phase 4 Feature (aktuell in Entwicklung). Wenn alle Child-Tickets geschlossen sind, wird der Parent automatisch via model.updated Signal-Handler geschlossen.
F: Wie werden Parent-Indikatoren zu Queue-Listen hinzugefügt?
A: Das Plugin nutzt zwei Mechanismen:
ParentTicketDecoration-Klasse erweitert osTickets QueueColumnAnnotation, um ein SQL-JOIN zum Zählen von Child-Tickets hinzuzufügenqueue-indicator.js holt Parent-Status via AJAX und fügt Icons dynamisch einF: Warum eigenständiger AJAX-Handler statt Signal-Routing?
A: Der eigenständige Handler (ajax-subticket.php) ist einfacher und wartbarer als Signal-basiertes Routing. Er bietet direkte, vorhersagbare Endpunkte ohne komplexe Dispatcher-Logik.
F: Wie funktioniert Auto-Linking für neue Subtickets?
A: Wenn du auf "Subticket erstellen" klickst, wird die Parent-ID in $_SESSION['subticket_parent'] gespeichert. Nach Ticket-Erstellung setzt der model.created Signal-Handler (onTicketCreated()) automatisch ticket_pid in der Datenbank.
F: Kann ich das Panel-Aussehen anpassen?
A: Ja, modifiziere die getPanelCSS()-Methode in class.SubticketPlugin.php. Alle Styles sind Inline-CSS für einfache Anpassung.
F: Wie aktiviere ich Debug-Logging?
A: Bearbeite class.SubticketPlugin.php und ändere Zeile 8:
define('SUBTICKET_DEBUG', true);
Debug-Logs werden nach /tmp/subticket-debug.log geschrieben.
F: Welche SQL-Queries werden ausgeführt?
A: Debug-Modus aktivieren und /tmp/subticket-debug.log prüfen. Beispiel-Queries:
-- Children abrufen
SELECT t.ticket_id, t.number, cdata.subject, s.name as status
FROM ost_ticket t
LEFT JOIN ost_ticket__cdata cdata ON t.ticket_id = cdata.ticket_id
LEFT JOIN ost_ticket_status s ON t.status_id = s.id
WHERE t.ticket_pid = 15;
-- Ticket verknüpfen
UPDATE ost_ticket SET ticket_pid = 15 WHERE ticket_id = 123;
F: Funktioniert das mit osTicket 1.17 oder älter?
A: Nein. Das Plugin benötigt osTicket 1.18.x für ordentliche Signal-Unterstützung und Datenbankstruktur. osTicket 1.17 und älter können unterschiedliche ticket_pid-Implementierungen haben.
F: Ist es kompatibel mit PHP 8.x?
A: Ja! Das Plugin ist mit PHP 7.4, 8.0, 8.1, 8.2 und 8.3 getestet. CI-Pipeline führt Tests auf allen Versionen aus.
F: Kann ich das mit PostgreSQL statt MySQL verwenden?
A: Das Plugin ist für MySQL/MariaDB ausgelegt. PostgreSQL-Unterstützung würde Modifikation der SQL-Queries erfordern (osTicket selbst unterstützt primär MySQL).
F: Funktioniert es mit Elasticsearch Queue Plugin?
A: Sollte funktionieren, aber nicht explizit getestet. Die Queue-Decoration hakt in osTickets Standard-Queue-System ein, also könnten Elasticsearch-Plugins es überschreiben.
Dieses Plugin wird unter der GNU General Public License v2 veröffentlicht, kompatibel mit osTicket Core.
Details siehe LICENSE.
Für Fragen oder Probleme erstelle bitte ein Issue auf GitHub:
Issue Tracker: https://github.com/markus-michalski/osticket-subticket-manager/issues
Beim Melden von Problemen bitte angeben:
php -v)Entwickelt von Markus Michalski
Beiträge willkommen!
Siehe CHANGELOG.md für Versionshistorie.