Dokumentation gibt es dazu im Rahmen des 1CRM Developer Guide, der neben weiteren Informationen unter https://1crm.com/developers/ auf der Seite von 1CRM Corp zu finden ist.

Wenig beschrieben sind allerdings bisher die PHP-Klassen, die im Kern von 1CRM einen API-Zugriff auf die Business-Logik ermöglichen. Hierbei geht es meist um die Suche nach CRM-Entitäten, den Zugriff auf Werte und Eigenschaften und nicht zuletzt auf das Speichern neuer Werte in einer Entität oder das Erstellen neuer Datensätze.

Kurz gesagt: die ListQuery ist für die Suche von Datensätzen verantwortlich und liefert ein ListResult zurück. Das ListResult wiederum enthält RowResults, die man für ein Update in ein RowUpdate umwandelt.

Auf github haben wir ein paar Erweiterungen für 1CRM veröffentlicht, https://github.com/visual4/1crmFormatPhoneNumbers ist eine in der sich sehr viele Aspekte der Erweiterbarkeit wiederfinden.

ListQuery zur Suche von Daten

Im einfachsten Anwendungsbeispiel habe ich die ID (den Primärschlüssel) eines Datensatzes in 1CRM und möchte einfach das Objekt erhalten, das Modul ist auch bekannt:

/** @var RowResult $rowResult */
$rowResult = ListQuery::quick_fetch('Account', $id);

Die Model-Namen wie hier Account beziehen sich dabei immer auf die Namen der Beans, meist Einzahl und immer zu finden im jeweiligen Modulverzeichnis. Bei diesem Code-Beispiel also unter modules/Accounts/models/bean.Account.php.

Wichtig: in den URLs zum Aufruf des Moduls wird immer der Verzeichnisname des Moduls verwendet, das wäre hier also index.php?module=Accounts.

Variante zwei ermöglicht den schnellen Zugriff auf eine Entität mithilfe eines bestimmten Wertes:

/** @var RowResult $rowResult */
$rowResult = ListQuery::quick_fetch_key('CompanyAddress', 'main', 1);

Hier wird die CompanyAddress gesucht, bei der main==1 ist.

Dazu muss man an der Stelle wissen, dass die Businesslogik von 1CRM genau einen Hauptsitz erlaubt. CompanyAddress bezieht sich dabei auf die Firma deren 1CRM wir gerade bearbeiten (Administration -> Firmeninformationen ganz unten).

Mögliche Feldnamen für die Suche findet man in diesem Fall unter: modules/CompanyAddress/models/bean.CompanyAddress.php

Bei ListQuery::quick_fetch_key() wird keine Sortierung vorgegeben – sollten mehrere Datensätze auf den Filter passen kann nicht vorhergesagt werden, welchen man zurückbekommt.

Das Ganze geht natürlich auch ausführlich, nichtstatisch:

$lq = new ListQuery('Contact');
// hierüber können Filter auf Felder des Modells und auf Felder von 1:n Relationen erstellt werden
// die addSimpleFilter Methode erlaubt auch Vergleichsoperatoren als weiteren Parameter
$lq->addSimpleFilter('last_name', 'Rafreider');
$lq->addSimpleFilter('primary_account.name', 'visual4 GmbH');
// über addFields kann angegeben werden, welche Felder zurückgegeben werden
// als zweites Feld wird hier ein Wert aus dem primary_account abgefragt,
// prinzipiell sind hier beliebige Relationstiefen möglich
$lq->addFields(['last_name', 'primary_account.name']);
// die Parameter sind: Offset, Limit, do_count und order_by
$listResult = $lq->runQuery(0, 20, false, 'last_name ASC');
foreach ($listResult as $rowResult) {
// add_flash_message erstellt eine Hinweismeldung
add_flash_message(
$rowResult->getField('last_name') . ': ' . $rowResult->getField('primary_account.name')
);
}

ListResult, wie kann ich auf die Ergebnisse zugreifen?

Die ListResult-Klasse implementiert ein Traversable, d.h. auf die einzelnen RowResults kann wie im vorhergehenden Beispiel am einfachsten mit foreach zugegriffen werden.

$listResult->getRows(); // gibt die Resultate als Array zurück

$listResult->getRowResults(); // gibt alle RowResults als Array zurück

RowResult-Entität und jetzt?

Das RowResult ist die Entität, also der Kontakt, die Firma oder der Benutzer. Das Wichtigste daran sind die Daten und diese Daten erhält man, wie im ausführlichen ListQuery-Beispiel gezeigt, mit der RowResult::getField()-Methode:

$lastName = $rowResult->getField('last_name');

Der Primärschlüssel einer Entität wird meist im Feld id gespeichert, aber eben nur meist. Um auf Nummer sicher zu gehen, gibt es die Methode RowResult::getPrimaryKeyValue().

$id = $rowResult->getPrimaryKeyValue();

RowUpdate, da ändert sich was!

Um Daten zu ändern brauche ich ein RowUpdate, um dieses zu erhalten existiert die factory-Methode RowUpdate::for_result():

$rowUpdate = RowUpdate::for_result($rowResult);

Um ein neues Objekt zu erstellen entsprechend RowUpdate::blank_for_model():

$rowUpdate = RowUpdate::blank_for_model('Contact');

Als zweiter Parameter (bei for_result() als dritter) kann hier die User-ID mitgegeben werden, das ist insbesondere hilfreich, wenn die Methode z.B. innerhalb eines Schedulers ohne aktiven Benutzer verwendet wird.

Werte werden am einfachsten über ein assoziatives Array an die Methode RowUpdate::set() übergeben:

$rowUpdate->set([
'first_name' => 'Björn',
'last_name' => 'Rafreider',
'email1' => 'br@example.com'
]);

Um sie danach zu validieren und zu speichern:

if ($rowUpdate->validate())$rowUpdate->save();
else add_flash_message($rowUpdate->getErrors(true));

Beim Speichern eines Datensatzes auf diesem Weg wird natürlich die gesamte Businesslogik von 1CRM ausgeführt, d.h. alle Hooks für before- und after-save werden berücksichtigt, genau wie Workflows und Benachrichtigungen im System.

Fazit

In der Praxis sehen wir immer wieder mit dem heißen Eisen gestrickte Erweiterungen, die Daten mithilfe von SQL auf Datenbankebene lesen oder schreiben – ich hoffe dieser Artikel zeigt, dass es nicht nur besser, sondern auch einfacher mithilfe der in 1CRM verfügbaren Klassen und Methoden geht.

Eine Dokumentation aller Möglichkeiten würde den Rahmen sprengen, gerne nehmen wir aber Ihre Fragen auf und ergänzen den Artikel.