Arbeiten mit Dateien ist in Shopware 6 an sich recht einfach, gerade seit die Media-Entity und deren Thumbnails ein Path-Feld haben, in dem der relative Pfad direkt angegeben werden kann. Wenn man den hat muss man nur noch den absoluten Pfad bauen. Wenn man z.B. in das public/ Verzeichnis will um dort etwas zu hinterlegen oder ein Media-File zu lesen kann man sich die Umgebungsvariable mit Symfony Project Root per Dependency Injection direkt in den Constructor seines Services geben und von da aus dahin navigieren. Von der aktuellen PHP-Datei aus ist es nicht so toll, da man nicht immer weiß wo das Plugin sich befindet. Z.B: kann es im custom-Folder oder irgendwo in vendor/ sich befinden.
<argument>%kernel.project_dir%</argument>
Und was ist wenn man die Dateien in einem Cluster-Betrieb über ein S3-Bucket an die Cluster-Nodes verteilt? Shopware 6.5 hat zum Glück nicht nur Flysystem dabei, sondern nutzt es auch richtig. Man kann sich direkt per Dependency Injection das privater oder das öffentliche Dateisystem geben lassen und dann ist es egal ob es auf einem FTP, in einem S3 Bucket oder im lokalen Dateisystem liegt.
namespace HPr\FSTest\Services;
use League\Flysystem\FilesystemOperator;
use Shopware\Core\Content\Media\MediaEntity;
class MediaTest {
public function __construct(private FilesystemOperator $filesystem){}
/**
* @throws FilesystemException
*/
public function md5Media(MediaEntity $media): string {
return md5($this->filesystem->read($media->getPath()));
}
}
Um nun das passende Dateisystem zu bekommen ist nicht viel nötig.
Public ist das öffentliche Verzeichnis, das man für Product-Bilder, CMS-Media oder auch andere Downloads nutzen kann, die jeder sehen darf. Dann gibt es auch das private Dateisystem, wo man alles wie Rechnungen und Dinge ablegt, die nicht jeder sahen darf und wo man den Zugriff am besten durch einen eigenen Controller kapselt. Die MediaEntity hat einen private-Flag, um anzugeben in welchem Dateisystem man die Datei findet.
Das Dateisystem selbst kann man in einer YAML-Datei in config/packages/ definieren. Wie man da z.B. seine Dateien in einem MinIO S3 Bucket ablegen kann, habe ich in einem Post vorher schon erklärt.
Da man beim einfachen Entwickeln nicht ein AWS S3-Bucket für die Entwickler bereit stellen möchte, kann man hier sehr gut MinIO verwenden. Es lässt sich schnell in docker-compose einbinden und die FileSystems von Shopware können den normalen S3-Adapter verwenden.
Oft will man ja beim Speichern von Dateien flexibel bleiben. Beim Entwickeln lokal speichern, im Produktivsystem in S3 und auf einem alten Test-System vielleicht noch auf einem FTP-Server oder in Redis.
Jeder hat schon mal so was geschrieben um wenigstens das native Filesystem und FTP zu abstrahieren, weil der FTP-Server nur vom produktiven System aus zu erreichen war oder so. Mein PHP Framework hat auch solche Klassen. Aber ich hatte keine Lust mehr diese noch mal anzupassen und eine brauchbare Struktur mit Factory und Interfaces dort endlich mal zu implementieren... was die Klassen (2006 geschrieben) an sich dringend nötig hätten.
Deswegen habe ich mich einige Sekunden im Internet umgeguckt und Flysystem gefunden. Das kann natives FS, FTP, S3, Redis, OneDrive, Azure File Storage.... also alles was man so braucht.
Ich habe es mal mit S3 getestet. Natürlich müsste man sich erst einmal eine brauchbare Factory schreiben, aber da kann man sicher in seinem System auf die alten Strukturen zurück greifen und muss dann nicht alles umbauen, wenn man auf Flysystem wechselt.