Symfony2 konzeptionelles Problem: allgemeine Bündel vs. spezifische

Edit: Die Best Practices von Symfony beantworten die meisten meiner Fragen.

Ich habe einige Fragen zu meiner Symfony2 App.

Es wird ein Frontend und ein Backend haben, und sie werden einen gemeinsamen Code benutzen (wie ein Datumsanzeigeprogramm, Paginator, einige häufig verwendete Vorlagen usw.).

Also habe ich ein FrontendBundle und ein BackendBundle erstellt, die jeweils zum Beispiel ihr jeweiliges Layout enthalten. Erste Frage: Ist es eine gute Vorgehensweise, Bundles für Frontend und Backend zu erstellen, die “allgemeine” Pakete sind, die nicht einmal einen Controller haben?

Zweite Frage: Ich habe in einem Kochbuch gelesen, dass ich meine Layouts nicht in Pakete, sondern in das Verzeichnis app / Resources / views / einfügen sollte. Ich habe bereits eine base.html.twig-Datei darin, und ich frage mich, ob ich meine Layouts auch dort einfügen sollte, wie eine frontend_layout.html.twig-Datei?

Ich habe ein Paket namens RootBundle erstellt, das alles enthält, was meine App im Frontend UND Backend benötigt. Ist das eine gute Übung oder nicht? Oder ich sollte ein dediziertes Bundle für jede vorgeschlagene functionalität erstellen, wie zum Beispiel ein PaginatorBundle, ein DateDisplayerBundle, etc? Es klingt komisch, dass ich ein “Verschiedenes” -Bündel habe, in dem alles enthalten ist, was ich nicht weiß. Wie machst du das?

   

Der neue Ansatz

Nach einigen Monaten, seitdem ich diese Antwort geschrieben habe, hat sich mein Ansatz geändert, also teile ich es mit der Community. Diese Antwort ist immer noch ziemlich populär und kann Neulinge zu dem Ansatz führen, den ich nicht mehr für den besten halte. Damit…

Jetzt habe ich nur noch ein App-spezifisches Bundle und ich nenne es AppBundle . Es gab einige Probleme mit dem alten Ansatz und hier sind einige von ihnen:

  • Eine Menge Bündel zu erstellen ist mühsam. Sie müssen eine Bundle-class und eine Reihe von Standard-Ordnern für jedes neue Bundle erstellen und dann aktivieren und seine Routen und DI und whatnot registrieren.

  • Unnötiger Hardcore-Entscheidungsprozess. Manchmal kann man sich nicht entscheiden, zu welchem ​​Bundle ein bestimmtes Ding gehört, weil es von mehr als einem Bündel benutzt wird. Und nachdem du einen halben Tag verbracht hast und dich endlich entscheidest, wo du es hinkriegen solltest, wirst du feststellen, dass du in ein paar Tagen oder Wochen nicht sofort sagen kannst, welches Bündel das Ding in sich trägt – weil die Entscheidung meistens nicht auf reiner Logik beruhte und man sich aufgrund eines Münzwurfs oder welcher Art auch immer entscheiden musste, um höhere Kräfte zur Hilfe zu bringen.

    Ich habe vorgeschlagen, CommonBundle für gängige Sachen in der Vergangenheit zu verwenden, aber dabei musst du viele unnötige Refactorings machen, um eine Sache von und nach CommonBundle zu CommonBundle basierend darauf, wie viele oder wenige Bündel das Ding später benutzen werden.

  • App-spezifische Bündel sind ohnehin voneinander abhängig. Wenn Leute zum ersten Mal die Idee von Bündeln kennenlernen, ist einer der Hauptgedanken, der ihnen durch den Kopf geht, etwas wie “Yay! Ich werde mir ein paar wiederverwendbare Bündel besorgen! “Diese Idee ist großartig und ich habe nichts dagegen; Das Problem ist, dass app-spezifische Bundles sowieso nicht wiederverwendbar sind – da sind sie voneinander abhängig. Vergessen Sie in diesem Fall die Wiederverwendung.

  • Keine Ahnung, wo Behat Features und Schrittdefinitionen zu platzieren sind. Dieses Problem hängt mit den vorherigen zusammen: Sie müssen die gleichen hirnlosen Bewegungen für jedes Bündel wiederholen und dann hardcore Entscheidungen treffen.

    Als ich anfing, Behat-Features zu schreiben, konnte ich mich nicht entscheiden, wo ich viele Features und Schrittdefinitionen platzieren sollte, weil sie zu mehreren Paketen gleichzeitig gehörten. CommonBundle schien noch schlimmer zu sein, sie in CommonBundle zu platzieren, denn das ist das letzte Bündel, nach dem ich FeatureBundle hätte. Also habe ich am Ende FeatureBundle .

Die Umstellung auf ein einzelnes Bündel triggerse alle diese Probleme.

Ich habe auch einige Leute gesehen, die ein separates Bündel haben, zum Beispiel für alle Entitäten. Ich mag diesen Ansatz auch nicht und schlage tatsächlich vor, Entitäten und andere nicht Symfony2-spezifische Sachen aus den Bündeln herauszuhalten .

Beachten Sie erneut, dass dieser neue Ansatz für anwendungsspezifische Bundles gilt. Offizielle Dokumente und andere Orte sind voller großartiger Ratschläge, wie Bundles zu strukturieren sind, die mit anderen geteilt und in zahlreichen Projekten wiederverwendet werden sollen. Ich schreibe auch solche Bündel . Aber was ich nach Monaten der Arbeit an Symfony2-Projekten herausgefunden habe, ist, dass es einen Unterschied zwischen den für die Wiederverwendung bestimmten Paketen und den anwendungsspezifischen gibt – ein Ansatz passt nicht für alle.

Und natürlich, wenn Sie sehen, dass in Ihrem App-spezifischen Bundle etwas wiederverwendbares entsteht, extrahieren Sie es einfach, legen Sie es in ein separates Repo und installieren Sie es als Anbieter.

Außerdem habe ich Subnamespaces viel aktiver benutzt, um das Paket logisch zu partitionieren – anstatt dafür eine Menge an Bündeln zu erstellen und all diese Probleme durchzugehen.

Der alte Ansatz

Es gibt keine festen Regeln oder silberne Kugeln, aber ich teile meine Herangehensweise, Dinge zu tun – vielleicht gibt es dir einen Einblick oder zwei.

Zuallererst habe ich nicht zwei allumfassende Bundles wie FrontendBundle und BackendBundle . Stattdessen haben meine Bundles sowohl Frontend- als auch Backend-Controller, Ansichten usw. Wenn ich also alles von meinem UserBundle abgesehen von Controllern und Ansichten, würde seine Struktur wie UserBundle aussehen:

 UserBundle ├── Controller │ ├── Admin │ │ └── UserController.php │ └── UserController.php ├── Resources │ └── views │ ├── Admin │ │ └── User │ │ ├── add.html.twig │ │ ├── delete.html.twig │ │ ├── edit.html.twig │ │ ├── form.html.twig │ │ └── index.html.twig │ └── User │ ├── edit.html.twig │ ├── sign-in.html.twig │ ├── sign-up.html.twig │ └── view.html.twig └── UserBundle.php 

Zweitens habe ich CommonBundle das ich für Sachen verwende, die von mehreren Bundles geteilt werden:

 CommonBundle ├── Resources │ ├── public │ │ ├── css │ │ │ ├── admin.css │ │ │ ├── common.css │ │ │ └── public.css │ │ └── img │ │ ├── add.png │ │ ├── delete.png │ │ ├── edit.png │ │ ├── error.png │ │ ├── return.png │ │ ├── success.png │ │ └── upload.png │ └── views │ ├── Admin │ │ └── layout.html.twig │ └── layout.html.twig └── CommonBundle.php 

Meine app/Resources/views/base.html.twig fast der Symfony Standard-Distribution:

 < !DOCTYPE html>    {{ block('title') | striptags | raw }} {% block stylesheets %}{% endblock %}   {% block body %}{% endblock %} {% block javascripts %}{% endblock %}   

Sowohl CommonBundle/Resources/views/layout.html als auch CommonBundle/Resources/views/Admin/layout.html erweitern app/Resources/views/base.html.twig . Die Vorlagen anderer Bundles erweitern eines dieser beiden Layouts, je nachdem, ob sie für das Frontend oder das Backend gedacht sind. Im Grunde benutze ich den Ansatz der Drei-Ebenen-inheritance .

Also, ich würde dein Date CommonBundle in CommonBundle . Je nach Komplexität kann es sich um eine Vorlage, ein Makro oder eine Twig- Erweiterung handeln .

Paginierung ist ein häufiges Problem, daher empfehle ich Ihnen, eines der vorhandenen Pakete zu verwenden, anstatt das Rad neu zu erfinden – wenn es natürlich Ihren Anforderungen entspricht.

Und ja, es ist völlig in Ordnung, Bundles ohne Controller oder Views usw. zu haben.

Ich schlage vor, ein DateDisplayerBundle und ein PaginatorBundle zu erstellen, anstatt den zugehörigen Code in ein allgemeineres Paket zu stecken. Dafür gibt es einige Gründe:

  • Die Rolle jedes Pakets ist sehr klar und Sie wissen, wo Ihr Code ist.
  • Das Teilen von functionen (Datumsanzeige, Paginator) zwischen verschiedenen Projekten ist einfacher, wenn Sie separate Bundles haben, im Gegensatz zu einem allgemeinen Bundle, das Sie dann möglicherweise zurückschneiden müssen.

Es gibt keine feste Regel, die besagt, dass Bündel Controller haben müssen. Bundles können eine beliebige Mischung aus Geschäftslogik, Vorlagen, Controllern und Konfiguration aufweisen, es gibt jedoch keine Einschränkungen hinsichtlich der Möglichkeiten, die Sie darin speichern können.

Auf der anderen Seite, wenn Ihre functionalität nicht sehr komplex ist, kann es nicht garantiert werden, dass sie in einem Paket enthalten ist. In diesem Fall könnten Sie eine Bibliothek in /vendor dafür erstellen. Symfony verwendet auf diese Weise eine Reihe von Bibliotheken (siehe Monolog und Doktrin zum Beispiel).

Was Ihre zweite Frage anbelangt, so liegt der Grund für das Speichern von Layouts in app\Resources\views darin, dass Sie bequem alle Ihre Layouts verfolgen können. Wenn Sie ein Projekt mit vielen Bundles haben, verlieren Sie möglicherweise den Überblick darüber, wo sich ein bestimmtes Layout befindet. Aber wenn Sie alle an einem zentralen Ort aufbewahren, wissen Sie immer genau, wo Sie suchen müssen. Wie bei vielen Dingen in Symfony2 ist dies keine Regel, die in Stein gemeißelt ist. Sie können Ihre Layouts einfach in einem Paket speichern, aber ich denke nicht, dass es die empfohlene Vorgehensweise ist.

Was deine Frage zu deinem allgemeinen Root-Paket betrifft, würde ich sagen, dass du in den meisten Fällen vermeiden solltest, eine Menge verschiedener Features in einem Bündel zu schuhen. Sehen Sie meine früheren Punkte über das Halten Ihrer Bündel spezifisch. Als ich anfing, mit Symfony2 zu entwickeln, hatte ich einige Probleme, zu bestimmen, welcher Code in welchem ​​Bundle gehen sollte. Ich war es nicht gewohnt, über Programmierung nachzudenken. Aber irgendwann beginnt man zu sehen, wie die einzelnen Teile des Puzzles passen, und das macht es einfacher, die Bündelstruktur zu bestimmen.