Während ich mit meinem Team an einem Symfony-Projekt arbeitete, musste ich bestimmte Value Object-Instanzen in einen meiner Dienste einfügen. Die Werte selbst mussten in diesem speziellen Fall anhand der in unserer .env-Datei bereitgestellten Werte festgelegt werden.
Ich könnte die String-Werte natürlich einfach direkt an meinen Dienst übergeben und den Dienst die Wertobjekte im Konstruktor instanziieren lassen, aber ich wollte sehen, ob es möglich ist, sie in der Datei „services.yaml“ zu konfigurieren und einzufügen stattdessen die vollständig instanziierten Objekte. Dies würde es mir ermöglichen, diese Objektinstanzen an mehrere Dienste zu übergeben und die Erstellung des Wertobjekts nicht in jedem einzelnen Dienst wiederholen zu müssen.
So habe ich es gemacht...
Unsere Anwendung nutzt das Twilio SDK. Wir haben verschiedene Dienste, die die SDK-Aufrufe umschließen, und sie müssen unsere umgebungsspezifischen Konfigurationswerte verwenden (den API-Schlüssel unseres Unternehmens für jede Umgebung usw.).
Die Twilio-API verwendet String-Identifikatoren oder SIDs. Jedem SID-Typ ist ein anderes Präfix aus zwei Buchstaben zugeordnet, gefolgt von 32 Zeichen bestehend aus den Ziffern 0 bis 9 und den Buchstaben A bis F (Groß- und Kleinbuchstaben).
Zum Beispiel:
Ich wollte sicherstellen, dass die Wertobjekte für jeden SID-Typ validieren, dass der übergebene Wert das richtige Präfix für diesen SID-Typ hat, und außerdem sicherstellen, dass die Zeichenfolge die richtige Länge hat und nur aus den zulässigen Zeichen besteht .
Jeder meiner SID-Typen verwendet dieselbe Validierungslogik und Funktionalität und unterscheidet sich nur durch das Präfix des SID-Typs. Daher ist es sinnvoll, ein Basismerkmal zu erstellen. Wenn Sie möchten, könnte dies auch eine abstrakte Klasse sein. Ich brauche das Konzept eines TwilioStringIdentifier in der App nicht als Parametertyp oder ähnliches, daher bevorzuge ich hier ein Trait gegenüber einer Abstract Class.
Diese Eigenschaft definiert eine abstrakte Methode getPrefixForSidType(), die jeder SID-Typ implementieren muss, um das richtige Präfix für diesen bestimmten Typ bereitzustellen. Es führt auch die Validierungslogik aus.
namespace App\Domain\Model\Twilio\Sid; use Assert\Assert; trait TwilioStringIdentifier { private readonly string $sid; abstract private function getPrefixForSidType(): string; public static function fromString(string $string): self { return new self($string); } public function __construct(string $sid) { Assert::that($sid) ->startsWith($this->getPrefixForSidType()) ->length(34) ->regex('/^[a-zA-Z]{2}[0-9a-fA-F]{32}$/') ; $this->sid = $sid; } public function asString(): string { return $this->sid; } }
Die Wertobjektklassen, die jeden der SID-Typen darstellen, sind einfach. Sie müssen lediglich das TwilioStringIdentifier Trait verwenden und das richtige Präfix über die Methode getPrefixForSidType() definieren.
namespace App\Domain\Model\Twilio\Sid; final readonly class AccountSid { use TwilioStringIdentifier; private function getPrefixForSidType(): string { return 'AC'; } }
Die anderen SID-Typklassen sind bis auf ihr definiertes Präfix identisch.
Da diese Wertobjekte in der gesamten Anwendung und mit verschiedenen zugehörigen Werten und nicht nur mit den globalen Werten unseres Unternehmens verwendet werden, brauchte ich eine Möglichkeit, in Dienste ein Objekt eines bestimmten Typs einzufügen, das bereits mit den definierten Werten instanziiert wurde in unserer .env-Datei
Ich wusste, dass Symfony die Möglichkeit hat, Dienste zu definieren, die über eine Factory instanziiert werden sollen, hatte aber (soweit ich mich erinnere) noch nie etwas über das Einfügen eines Objekts gesehen, das das Ergebnis eines Methodenaufrufs von irgendwo anders war. Ich wusste auch, dass an diese Factory-Methoden Argumente übergeben werden könnten, ich war mir nur nicht sicher, wie ich das mit einer Value Object-Instanz machen sollte.
Mit der Dienstdefinition von Symfony können Sie jeden Dienst benennen. Normalerweise geschieht dies mit dem Namen der Service-Klasse:
App\Path\To\My\Service: class: App\Path\To\My\Service arguments: []
Dieser Dienstname muss jedoch nicht mit dem Klassennamen übereinstimmen. Es könnte app.my_service oder FooBarBazService oder was auch immer sein.
Was passiert also, wenn ich einen Dienst mit einem eindeutigen Namen erstelle, der die instanziierte Instanz des von mir benötigten Wertobjekts ist? Ich könnte den .env-Wert als Argument übergeben und dann diese Objektinstanz in meine Serviceklassen einfügen!
# Create services named with a Global "namespace" Global\Twilio\Sid\Account: factory: ['App\Domain\Model\Twilio\Sid\AccountSid', 'fromString'] arguments: ['%env(TWILIO_ACCOUNT_SID)%'] Global\Twilio\Sid\Api: factory: ['App\Domain\Model\Twilio\Sid\ApiSid', 'fromString'] arguments: ['%env(TWILIO_API_SID)%'] Global\Twilio\Sid\Application: factory: ['App\Domain\Model\Twilio\Sid\ApplicationSid', 'fromString'] arguments: ['%env(TWILIO_APP_SID)%']
Übergeben Sie dann diese Dienste (Objekte) über ihre benannten Argumente an meinen Twilio-Dienst:
App\Service\Vendor\Twilio\TwilioService: arguments: $accountSid: '@Global\Twilio\Sid\Account' $apiSid: '@Global\Twilio\Sid\Api' $applicationSid: '@Global\Twilio\Sid\Application' $apiSecret: '%env(TWILIO_API_SECRET)%'
Jetzt kann meine Serviceklasse damit rechnen, die vollständig instanziierten Value Object-Instanzen zu erhalten:
namespace App\Service\Vendor\Twilio; use App\Domain\Model\Twilio\Sid\AccountSid; use App\Domain\Model\Twilio\Sid\ApiSid; use App\Domain\Model\Twilio\Sid\ApplicationSid; final readonly class TwilioService { public function __construct( private AccountSid $accountSid, private ApiSid $apiSid, private ApplicationSid $applicationSid, private string $apiSecret ) {} }
Voila!
Symfony ist flexibel genug und intuitiv genug, dass es einfach war, herauszufinden, wie das geht. Da ich nirgendwo eine schnelle Referenz dafür finden konnte, dachte ich, ich schreibe dies als Referenz für Future Me und alle anderen auf, die möglicherweise etwas Ähnliches tun müssen
Prost und viel Spaß beim Codieren!
Das obige ist der detaillierte Inhalt vonWertobjekte in einen automatisch verdrahteten Symfony-Dienst einfügen. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!