Resource Handling im Repository

Avatar von Maximilian Berghoff

PHP-Applikationen sind inzwischen stark modularisiert, composer.json ist inzwischen kaum noch aus dem Projektalltag wegzudenken. Doch dadurch entstehen auch neue Probleme. Irgendwie wollen verschiedene Resourcen (CSS, JS, Templates, …) aus externen Libraries in die Applikation eingebunden werden. Im Symfony-Umfeld hilft dabei in Teilen zwar eine saubere Ordnerstruktur und das Assets-Handling, doch nicht alles ist ein Symfony-Bundle. Ende letzten Jahres hat uns dann Bernhard Schussek (@Webmozart) ein Tool vorgestellt, das hier Abhilfe schafft: Puli. Weitere Infos zu Puli finden sich in seinem Blog.

Repository

Es ist aber nicht nur das File-Handling, was Puli so interessant macht. Es bietet zudem Interfaces an, mit denen sich eigene Repositories implementieren lassen. Warum dann nicht ein Repository auf einem Datenbestand aufsetzen, der von Grund auf schon wie ein Verzeichnis-/Dateibaum aussieht? Gesagt, getan. Das Symfony-CMF beherbergt insgesamt drei (Code-)Repositories, die genau das tun.

Die Resouce-Komponente implementiert RepositoryInterfaces, das heißt, hier finden wir ein PhpcrOdmRepository und ein PhpcrRepository. Je nach Vorliebe kann auf dem im PHPCR persistierten Baum entweder mit PHPCR-Session oder mit dem DoctrinePhpcrODM zugegriffen werden. Wie das so bei einem Interface üblich ist, ist von außen kaum ein Unterschied bemerkbar, nur die Resourcen sind eben andere.

Um ein Beispiel zu generieren, legen wir doch einmal einen simplen Content mit einem Titel und einem Body unter dem Pfad /cms/content/blog/example ab.

use Symfony\Cmf\Component\Resource\Repository\PhpcrOdmRepository;

$phpcrOdmRepsoitory = new PhpcrOdmRepository($manager, '/cms/content');
$phpcrOdmRepositoy->get('/blog/example');

Das Repository braucht nur den DocumentManager und einen Basispfad. Der definiert im Grunde das Verzeichnis, auf dem das Repository arbeitet. /cms/content/ ist also der Root-Pfad des so definierten Repositories und get(‚/blog/example) liefert dann eine Resource mit dem Content.

Als Resultat erhält man ein PhpcrOdmResource-Objekt, das als Payload den Content beinhaltet, den wir persistiert haben. Mit dem Resource-Bundle wird die Symfony-Integration bewerkstelligt. Dazu wird eine Konfigurationsmöglichkeit für die Repositories geschaffen:

cmf_resource:
    repositories:
        repository_phpcr_odm:
            type: doctrine_phpcr_odm
            basepath: /cms/content/odm

        repository_phpcr:
            type: doctrine_phpcr
            basepath: /cms/content/phpcr

Diese Konfiguration schafft nun die Möglichkeit, dass sowohl ein PHPCR als auch ein PHPCR-ODM-Repository aus einer Factory geliefert werden, und auf unterschiedlichen Sub-Bäumen gearbeitet werden kann:

$phpcrRespository = $this->container->get('cmf_resource.registry')->get('repository_phpcr_odm');

$phpcrOdmRespository = $this->container->get('cmf_resource.registry')->get('repository_phpcr');

Diese Repositories arbeiten dann auf den oben definierten Basispfaden. Der Teil container->get() sollte selbstverständlich in eine Servicedefinition ausgelagert werden. Hier dient es nur der Veranschaulichung.

Dann wäre zu aller letzt noch das ResourceRestBundle, das konfigurierte Repositories an einer REST-API exponiert. Ein einfaches Mapping von Repository und Content-Klasse …

cmf_resource_rest:
    payload_alias_map:
        blog:
            repository:repository_phpcr_odm
            type: "AppBundle\\Document\\DemoSeoContent"

… und schon sollte …

GET /api/repository_phpcr_odm/blog/example HTTP/1.1
Host: my-blog.loc
Accept: application/json

… funktionieren. Wer sich den URL anschaut, sieht eigentlich, dass er von dem Handling im Code nicht sehr weit entfernt ist. repository_phpcr_odm ist der Alias für das Repository und /blog/example der selbe Pfad, wie ich ihn dem Repository in get() übergeben hätte. Das Resultat sieht daraufhin so aus:

{
  "repository_alias": "repository_phpcr_odm",
  "repository_type": "doctrine_phpcr_odm",
  "payload_alias": "blog",
  "payload_type": "AppBundle\\Document\\DemoSeoContent",
  "path": "\/blog\/example",
  "node_name": "example",
  "label": "example",
  "repository_path": "\/blog\/example",
  "children": [],
  "payload": {
    "title": "Demo title",
    "body": "Body of demo content"
  }
}

Back to the Roots

Puli ist ja im Grunde angetreten, um Dateien mit einem Repository (oder mehreren) unter einen Hut zu bringen. Wenn dem so ist, müsste ja jetzt auch …

GET /api/default/snippet1.html HTTP/1.1
Host: my-blog.loc
Accept: application/json

… funktionieren. Tut es auch, wenn ich dafür ein Repository definiere:

cmf_resource:
    repositories:
        default:
            type: filesystem
            base_dir: "%kernel.root_dir%/Resources/views/snippets

Danach erhalte ich auch mein Template schön in einer Resource samt Metadaten verpackt:

{
    "repository_alias": "default",
    "repository_type": "filesystem",
    "payload_alias": null,
    "payload_type": null,
    "path": "\/snippet1.html",
    "node_name": "snippet1.html",
    "label": "snippet1.html",
    "repository_path": "\/snippet1.html",
    "children": [],
    "body": "

Snippet 1

“ }

Aber warum sollten denn Templates an einer API exponiert werden? Weil immer mehr Rendering für JavaScript-Applikationen dem Client verantwortet wird, also immer mehr und vor allem kleinere (Angualar-Direktiven) Templates verlangt werden. Hier die API zu vereinfachen und für den Client stabil zu halten wäre eine Aufgabe, die sich mit dem Repository leicht erledigen lässt. Änderungen am Dateisystem auf dem Server sollten den Client dann nicht mehr interessieren, da dann nur noch das Mapping des Repositories angepasst wird. Die API bleibt gleich.

Ausblick

Aktuell wird gerade daran gearbeitet, über Repositories Resourcen zu bearbeiten oder gar zu löschen. In diesen Tagen werden auch die WIP PRs zu dem Thema gemerged. Im ersten Schritt wird als „bearbeiten“ nur ein move und ein rename umgesetzt, da das eigentlich Editieren oder gar Anlegen größere Herausforderungen bereithält.

Avatar von Maximilian Berghoff

Kommentare

3 Antworten zu „Resource Handling im Repository“

  1. Resource Handling im Repository https://t.co/g2B0R9gyIT via @mayflowerphp /cc @dantleech

  2. Frisch im Blog: Resource Handling im Repository https://t.co/s5SdUKY0sO

  3. Für alle die es verpasst haben: „Resource Handling im Repository“ https://t.co/g2B0R9gyIT via @mayflowerphp #symfony-cmf #puli #symfony

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert


Für das Handling unseres Newsletters nutzen wir den Dienst HubSpot. Mehr Informationen, insbesondere auch zu Deinem Widerrufsrecht, kannst Du jederzeit unserer Datenschutzerklärung entnehmen.