Wer aus PHP anbindet, muss Kopfzeilen, Cursor und Fehlerformen nicht selbst
nachbauen. Das Paket peritio/api-client kennt jede Route dieser Seite und braucht
nur PHP 8.1 mit ext-curl.
Einbinden
peritio-php-sdk.zip herunterladen
(41 KB)
Entpacken, etwa nach lib/peritio-php-sdk, und in der eigenen
composer.json einbinden:
"autoload": {
"psr-4": { "Peritio\\Api\\": "lib/peritio-php-sdk/src/" }
}
Ohne Composer genügt ein eigener Autoloader auf src/. Die README im
Archiv beschreibt alle Optionen.
use Peritio\Api\Client;
$peritio = new Client(getenv('PERITIO_API_KEY'));
$peritio->ping();
Den Schlüssel in eine Umgebungsvariable legen, nicht in den Code.
Abgleich und Listen
$person = $peritio->personen()->setzenNachFremdId('P-4711', [
'vorname' => 'Mia',
'nachname' => 'Sander',
'email' => '[email protected]',
]);
$peritio->klassen()->aufnehmen(12, $person['id']);
foreach ($peritio->personen()->alle(['klasse' => 12]) as $p) {
echo $p['nachname'], "\n";
}
alle() blättert selbst weiter; liste() liefert eine
Seite samt naechsterCursor.
Themen und Zielstufen
Das Thema sagt, worum es geht; die Zielstufe, bis wohin es sitzen muss – 1 erinnern
bis 6 erschaffen. Erst beides zusammen macht aus Ergebnissen eine Aussage.
$thema = $peritio->themen()->anlegen([
'titel' => 'Auskunft am Telefon',
'zielstufe' => 3,
]);
// "noch nicht entschieden" ist eine gültige Aussage
$peritio->themen()->aendern($thema['id'], ['zielstufe' => null]);
// Themengruppen ordnen dagegen Kurse - die gueltigen Werte fuer themengruppe_id
foreach ($peritio->themen()->gruppen() as $gruppe) {
echo $gruppe['id'], ' ', $gruppe['titel'], "\n";
}
Themen sind nicht nach Einrichtungen getrennt: Dasselbe Thema trägt oft
die Fragen mehrerer Kurse, auch verschiedener Häuser. Wer hier schreibt oder löscht,
wirkt überall – genau wie in der Verwaltung.
Fallszenarien
Ein Szenario ist ein Graph aus Lagen und Entscheidungen. Vor dem Schreiben wird er
gelesen: unerreichbare Szenen, Lagen ohne Ausgang und Fälle, die sich nicht gut
ausgehen lassen, enden mit 422 – und zwar mit allen Mängeln auf einmal.
$peritio->kurse()->szenarioSetzen($kursId, $seminarId, [
'schluessel' => 'anruf-zeitdruck',
'titel' => 'Der Anruf unter Zeitdruck',
'thema' => 'Auskunft am Telefon',
'start' => 'anruf',
'szenen' => [
'anruf' => [
'text' => 'Am Telefon verlangt jemand Auskunft über einen Kollegen.',
'optionen' => [
['text' => 'Rückruf anbieten', 'ziel' => 'gut'],
['text' => 'Auskunft geben', 'ziel' => 'schlecht'],
],
],
'gut' => ['text' => 'Sie rufen zurück.', 'ende' => 'gut',
'lehre' => 'Ein Rückruf klärt, wer fragt.'],
'schlecht' => ['text' => 'Die Auskunft ging an eine fremde Person.',
'ende' => 'schlecht', 'lehre' => 'Am Telefon sieht man niemanden.'],
],
]);
Erkannt wird am schluessel: Derselbe Aufruf legt an und schreibt fort.
Szenen behalten dabei ihre Kennung, solange ihr Schlüssel bleibt – gegangene Durchgänge
bleiben lesbar.
Spickzettel und Werkstatt
Karten und Werkstatt-Vorlagen gehören zusammen und werden zusammen gesetzt –
wie in der Kursdatei. Eine weggelassene Liste bleibt unverändert, eine leere löscht
ihren Teil.
$peritio->kurse()->spickzettelSetzen($kursId, [
'karten' => [
['bereich' => 'HTML', 'titel' => 'Überschriften', 'sprache' => 'html',
'text' => 'h1 bis h6 gliedern die Seite.', 'code' => 'Titel
',
'thema' => 'Aufbau einer Seite'],
],
]);
Steht bei einer Karte ein thema, erscheint sie im Training als Hilfe
zu Fragen dieses Themas. Ein unbekannter Titel ist kein Fehler – die Karte steht dann
nur auf der Nachschlageseite.
Unterlagen und Verweise
Am Kurs oder am Seminar liegen Dateien, Verweise ins Netz und Podcasts – für
Lernende dasselbe: etwas zum Nachschlagen neben dem Seminar.
$peritio->kurse()->materialHochladen($kursId, 'merkblatt.pdf', $inhalt, [
'seminar_id' => $seminarId,
'titel' => 'Merkblatt Erste Hilfe',
]);
$peritio->kurse()->materialVerweis($kursId, 'Gesetzestext',
'https://www.gesetze-im-internet.de/…');
// Titel, Platz und "einfache Sprache" aendern, ohne die Datei neu zu senden
$peritio->kurse()->materialAendern($kursId, $materialId, [
'titel' => 'Merkblatt Erste Hilfe (Stand 2026)',
'reihenfolge' => 20,
]);
Verweise nehmen nur http und https an. Beim Ändern der
Angaben bleibt die Datei unberührt, auch ihr Dateiname. Den Inhalt tauscht ein eigener
Aufruf aus – Kennung und Name bleiben, und damit jede Folie und jede Aufgabe, die auf
die Datei zeigt. Der neue Inhalt muss zur Endung der vorhandenen Datei passen.
$peritio->kurse()->materialDateiErsetzen($kursId, $materialId, file_get_contents('schema-neu.png'));
Kursbild
Das Bild im Kopf des Kurses und auf seiner Kachel: PNG, JPEG oder WebP, im
Verhältnis 8:3 mindestens 1920 × 720 Pixel. Was davon abweicht, wird mittig
beschnitten; ein kleineres Bild wird mit 422 abgewiesen.
$peritio->kurse()->bildSetzen($kursId, file_get_contents('kopf.jpg'));
$peritio->kurse()->bildLoeschen($kursId); // zurück zum Vorgabebild
Fragen und Antworten
Prüfungsinhalte haben ein eigenes Recht: Wer Folien und Material pflegt, liest
den Fragenkatalog nicht mit. Angelegt wird im Aufbau der Kursdateien, geprüft von
derselben Klasse – die Aufgabenform ergibt sich aus dem, was dasteht.
$peritio->fragen()->anlegen($kursId, $seminarId, [
[
'text' => 'Welche Klausel filtert Zeilen?',
'antworten' => ['WHERE', 'SELECT', 'ORDER BY', 'LIMIT'],
'thema' => 'SQL-Grundlagen',
'stufe' => 2,
],
]);
// Stilllegen statt aendern: An einer Frage haengen abgegebene Antworten
$peritio->fragen()->aktivSetzen($kursId, $frageId, false);
Text und Antworten einer Frage stehen fest, sobald sie da ist. Eine geänderte
Frage ist eine andere Frage, und die Ergebnisse der alten wären nicht mehr zu
deuten; der Weg ist stilllegen und neu anlegen. Löschen geht nur, solange niemand
geantwortet hat – sonst kommt ein 409.
Die Fassung in einfacher Sprache ist dieselbe Frage in anderen Worten. Sie lässt
sich beim Anlegen mitgeben (text_leicht, kontext_leicht,
antworten_leicht) und jederzeit nachtragen, auch wenn schon geantwortet
wurde. Die Antworten werden über ihren genauen Wortlaut zugeordnet; stimmt einer
nicht, kommt ein 422, und nichts wird geschrieben.
$peritio->fragen()->leichtSetzen($kursId, $frageId, [
'text_leicht' => 'Welches Wort filtert Zeilen?',
'antworten_leicht' => [
['antwort' => 'ORDER BY', 'leicht' => 'ORDER BY (sortiert)'],
],
]);
Ebenso lassen sich Einordnung und Begleittexte einer bestehenden Frage ändern:
Thema, Stufe, Kontext und die Erklärung, die im Training nach der Antwort erscheint.
Nichts davon ändert, was gefragt und was als richtig gewertet wird.
$peritio->fragen()->nachpflegen($kursId, $frageId, [
'thema' => 'SQL-Grundlagen',
'stufe' => 3,
'erklaerung' => 'WHERE filtert Zeilen, bevor sortiert und begrenzt wird.',
]);
Das Bild einer Hotspot-Aufgabe muss im Material des Kurses liegen, bevor die
Aufgabe angelegt wird; sonst kommt ein 422.
Auch die Sachaufgabe gehört zu den Aufgabenformen: ein Text mit markierten
Angaben und dazu {"sachaufgabe": {"frage": "…", "ergebnis": 7}}
im Antwortteil.
Der SQL-Baukasten braucht nur die Musterlösung:
{"sqlbaukasten": {"loesung": "SELECT name FROM produkte WHERE preis > 100;"}}.
Aus ihr entstehen der Vergleich und das Angebot an Bausteinen. Erlaubt sind SELECT, FROM, WHERE mit
Vergleichen, AND und OR sowie ORDER BY; alles andere wird mit 422 abgewiesen. Dazu können
stufe (1 bis 3), ablenker (spalten, tabellen,
werte), spaltenfolge, ziele und bereiche kommen.
bereiche legt feste Bereiche auf die Arbeitsfläche: true für alle angebotenen
Klauseln oder eine Liste wie ["select", "from"]. auch nennt weitere Abfragen,
die als richtig gelten.
Folien einzeln ändern
Ein ganzer Kursabgleich gleicht alle Folien eines Seminars ab. Folien, die sich
wiedererkennen lassen – gleicher Inhalt oder gleiche Art und gleicher Titel –,
bleiben dieselben und behalten den Folienfortschritt der Lernenden; nur neu angelegte
gelten als ungesehen, und was im Satz fehlt, entfällt. Für eine Korrektur an einer
Folie ist das trotzdem zu grob, dafür gibt es eigene Wege.
$folien = $peritio->kurse()->folien($kursId, $seminarId);
$peritio->kurse()->folieAendern($kursId, $folien['daten'][0]['id'], [
'text' => 'Erst melden, dann handeln.',
]);
// Ausblenden statt löschen - die Folie bleibt für später erhalten
$peritio->kurse()->folieAendern($kursId, $alteFolie, ['aktiv' => false]);
$peritio->kurse()->folienOrdnen($kursId, $seminarId, [12, 10, 11]);
Aufgaben in Einführungsfolien
Eine Einführung soll die Lernenden etwas tun lassen. Eine Folie nimmt deshalb
eine Aufgabe an: Text und Antworten wie bei einer Frage, dazu eine Kennung, die beim
Überarbeiten gleich bleibt. Erlaubt sind die Formen, die der Browser selbst wertet –
Auswahl, Mehrfachauswahl, Reihenfolge, Richtig/Falsch, Lückentext, Markieren,
Zuordnen, Gruppieren, Diagnose, Berechnung und Sachaufgabe.
$peritio->kurse()->folieAnlegen($kursId, $seminarId, [
'titel' => 'Was fehlt im Vertrag?',
'text' => 'Sieh dir den Vertrag an.
',
'aufgabe' => [
'kennung' => 'f01-pflichtangaben',
'text' => 'Welche zwei Pflichtangaben fehlen?',
'antworten' => ['mehrfach' => ['richtig' => ['Probezeit', 'Vergütung'], 'falsch' => ['Lieblingsfarbe']]],
'erklaerung' => 'Probezeit und Vergütung gehören in jeden Ausbildungsvertrag.',
'bezug' => ['bild' => 'vertrag.svg', 'titel' => 'Vertrag ansehen'],
],
]);
Die Aufgabe steht am Ende des Folientexts oder an der Stelle von
{{aufgabe}}. aufgabe_leicht trägt dieselbe Aufgabe in
einfacher Sprache; fehlt sie, steht in der leichten Fassung der Folie die Aufgabe im
Standardwortlaut. "aufgabe": null nimmt sie heraus. Für Lernende gilt die
Folie erst als erledigt, wenn die Aufgabe abgegeben ist.
Gespeichert wird die Aufgabe als Markup im Folientext. Beim Lesen kommt deshalb
der Text mit dem Markup zurück, nicht das Feld – so bleibt lesen, ändern, zurückschicken
verlustfrei.
Herausforderung
Die Herausforderung eines Kurses prüft, ob das Gelernte in einer neuen Lage trägt:
Transferkarten mit einem Prinzip und Aufgaben dazu. Karten und Aufgaben werden an ihrem
schluessel wiedererkannt. Was im Rumpf fehlt, wird stillgelegt und nicht
gelöscht. Recht: fragen.
$stand = $peritio->fragen()->herausforderung($kursId);
$stand['karten'][0]['aufgaben'][0]['hinweis'] = 'Wer wird Eigentümer der Ware?';
$peritio->fragen()->herausforderungSetzen($kursId, ['probe' => true] + $stand); // nur prüfen
$peritio->fragen()->herausforderungSetzen($kursId, ['freigeben' => true] + $stand); // schreiben und zeigen
Jede Aufgabe braucht eine Lage, eine Frage und Optionen; genau eine Option trägt
fehlue – die Antwort, zu der greift, wer das Prinzip nicht übertragen hat.
Desktop-Simulation
Eine Welt der Desktop-Simulation ist ein Baum aus Bildschirmen und Übergängen, dazu
Aufgaben mit Start und Ziel. Welten gehören zu keinem Kurs und gelten für alle
Einrichtungen. Welche es gibt, zeigt desktopwelten() jedem Schlüssel mit dem
Recht inhalte; Inhalt lesen und schreiben geht nur mit Katalogpflege.
$welt = $peritio->kurse()->desktopwelt('win11-netzwerk');
$peritio->kurse()->desktopweltSetzen('win11-netzwerk', ['probe' => true] + $welt);
Vor dem Schreiben wird geprüft, was beim Durchklicken niemand findet: Jeder Knoten
muss vom Start aus erreichbar sein, und das Ziel jeder Aufgabe von ihrem Start.
Rahmenplan lesen
Der Ausbildungsrahmenplan kommt als Baum: Abschnitte, darin Positionen, darin
Lernziele und Zeiten. Die Verschachtelung ist die Gliederung der Verordnung.
$plan = $peritio->berufe()->rahmenplan(335);
foreach ($plan['abschnitte'] as $abschnitt) {
echo $abschnitt['kuerzel'], ' ', $abschnitt['titel'], "\n";
foreach ($abschnitt['positionen'] as $position) {
echo ' ', $position['kuerzel'], ' ', $position['titel'],
' (', count($position['lernziele']), " Lernziele)\n";
}
}
Welche Berufe ein Fachbereich ausbildet, steht unter
berufe()->jeFachbereich($id); gesetzt wird die Liste mit
fachbereichSetzen($id, [1, 2]).
Fehler als Ausnahmen
Jeder Code wird zu einer eigenen Ausnahme unter Peritio\Api\Fehler:
RechtFehlt, NichtGefunden, Konflikt,
Ungueltig (mit $e->feld) und weitere. Jede trägt
$e->anfrageId.
try {
$peritio->personen()->loeschen($id);
} catch (Fehler\Konflikt) {
$peritio->personen()->loeschen($id, mitErgebnissen: true);
}
Wiederholen ohne Doppel
Anlegen und Ändern bekommen automatisch einen Idempotency-Key. Nach
einem Netzfehler oder 5xx wiederholt die SDK deshalb gefahrlos, bei
429 wartet sie Retry-After ab.
Wer ein Importskript neu starten können will, gibt einen eigenen Schlüssel mit:
anlegen($daten, idempotenz: 'import-P-4711').