Δομή Καταλόγου της Εφαρμογής
Πώς να σχεδιάσετε μια σαφή και επεκτάσιμη δομή καταλόγων για έργα στο Nette Framework; Θα σας δείξουμε δοκιμασμένες πρακτικές που θα σας βοηθήσουν να οργανώσετε τον κώδικά σας. Θα μάθετε:
- πώς να χωρίσετε λογικά την εφαρμογή σε καταλόγους
- πώς να σχεδιάσετε τη δομή ώστε να επεκτείνεται καλά με την ανάπτυξη του έργου
- ποιες είναι οι πιθανές εναλλακτικές και τα πλεονεκτήματα ή μειονεκτήματά τους
Είναι σημαντικό να αναφέρουμε ότι το ίδιο το Nette Framework δεν επιμένει σε καμία συγκεκριμένη δομή. Είναι σχεδιασμένο έτσι ώστε να μπορεί εύκολα να προσαρμοστεί σε οποιεσδήποτε ανάγκες και προτιμήσεις.
Βασική Δομή Έργου
Παρόλο που το Nette Framework δεν υπαγορεύει καμία σταθερή δομή καταλόγων, υπάρχει μια δοκιμασμένη προεπιλεγμένη διάταξη με τη μορφή του Web Project:
web-project/ ├── app/ ← κατάλογος με την εφαρμογή ├── assets/ ← αρχεία SCSS, JS, εικόνες..., εναλλακτικά resources/ ├── bin/ ← σενάρια για τη γραμμή εντολών ├── config/ ← διαμόρφωση ├── log/ ← καταγεγραμμένα σφάλματα ├── temp/ ← προσωρινά αρχεία, cache ├── tests/ ← δοκιμές ├── vendor/ ← βιβλιοθήκες εγκατεστημένες από τον Composer └── www/ ← δημόσιος κατάλογος (document-root)
Μπορείτε να τροποποιήσετε αυτή τη δομή ελεύθερα σύμφωνα με τις
ανάγκες σας – να μετονομάσετε ή να μετακινήσετε φακέλους. Στη
συνέχεια, αρκεί μόνο να ενημερώσετε τις σχετικές διαδρομές προς τους
καταλόγους στο αρχείο Bootstrap.php
και ενδεχομένως στο
composer.json
. Τίποτα περισσότερο δεν χρειάζεται, καμία πολύπλοκη
επαναδιαμόρφωση, καμία αλλαγή σταθερών. Το Nette διαθέτει έξυπνη
αυτόματη ανίχνευση και αναγνωρίζει αυτόματα τη θέση της εφαρμογής,
συμπεριλαμβανομένης της βασικής της διεύθυνσης URL.
Αρχές Οργάνωσης Κώδικα
Όταν εξερευνάτε για πρώτη φορά ένα νέο έργο, θα πρέπει να μπορείτε να
προσανατολιστείτε γρήγορα σε αυτό. Φανταστείτε ότι ανοίγετε τον
κατάλογο app/Model/
και βλέπετε αυτή τη δομή:
app/Model/ ├── Services/ ├── Repositories/ └── Entities/
Από αυτό, μπορείτε να συμπεράνετε μόνο ότι το έργο χρησιμοποιεί κάποιες υπηρεσίες, repositories και entities. Δεν μαθαίνετε τίποτα για τον πραγματικό σκοπό της εφαρμογής.
Ας δούμε μια διαφορετική προσέγγιση – οργάνωση ανά τομείς:
app/Model/ ├── Cart/ ├── Payment/ ├── Order/ └── Product/
Εδώ είναι διαφορετικά – με την πρώτη ματιά είναι σαφές ότι πρόκειται για ένα e-shop. Τα ίδια τα ονόματα των καταλόγων αποκαλύπτουν τι μπορεί να κάνει η εφαρμογή – λειτουργεί με πληρωμές, παραγγελίες και προϊόντα.
Η πρώτη προσέγγιση (οργάνωση ανά τύπο κλάσης) φέρνει στην πράξη μια σειρά προβλημάτων: ο κώδικας που σχετίζεται λογικά είναι διάσπαρτος σε διαφορετικούς φακέλους και πρέπει να πηδάτε μεταξύ τους. Γι' αυτό θα οργανώσουμε ανά τομείς.
Χώροι Ονομάτων
Είναι σύνηθες η δομή καταλόγων να αντιστοιχεί στους χώρους ονομάτων
στην εφαρμογή. Αυτό σημαίνει ότι η φυσική θέση των αρχείων αντιστοιχεί
στο namespace τους. Για παράδειγμα, μια κλάση που βρίσκεται στο
app/Model/Product/ProductRepository.php
θα πρέπει να έχει το namespace
App\Model\Product
. Αυτή η αρχή βοηθά στον προσανατολισμό στον κώδικα και
απλοποιεί την αυτόματη φόρτωση (autoloading).
Ενικός vs Πληθυντικός Αριθμός στα Ονόματα
Παρατηρήστε ότι για τους κύριους καταλόγους της εφαρμογής
χρησιμοποιούμε ενικό αριθμό: app
, config
, log
, temp
,
www
. Το ίδιο και μέσα στην εφαρμογή: Model
, Core
,
Presentation
. Αυτό συμβαίνει επειδή καθένας από αυτούς
αντιπροσωπεύει μια ενιαία, ολοκληρωμένη έννοια.
Ομοίως, για παράδειγμα, το app/Model/Product
αντιπροσωπεύει τα πάντα
γύρω από τα προϊόντα. Δεν θα το ονομάσουμε Products
, επειδή δεν είναι
ένας φάκελος γεμάτος προϊόντα (αυτό θα σήμαινε ότι θα υπήρχαν αρχεία
nokia.php
, samsung.php
). Είναι ένας namespace που περιέχει κλάσεις για
την εργασία με προϊόντα – ProductRepository.php
, ProductService.php
.
Ο φάκελος app/Tasks
είναι στον πληθυντικό αριθμό επειδή περιέχει
ένα σύνολο ανεξάρτητων εκτελέσιμων σεναρίων – CleanupTask.php
,
ImportTask.php
. Καθένα από αυτά είναι μια ξεχωριστή μονάδα.
Για λόγους συνέπειας, συνιστούμε να χρησιμοποιείτε:
- Ενικό αριθμό για namespace που αντιπροσωπεύει μια λειτουργική ενότητα (byť pracující s více entitami)
- Πληθυντικό αριθμό για συλλογές ανεξάρτητων μονάδων
- Σε περίπτωση αβεβαιότητας ή αν δεν θέλετε να το σκεφτείτε, επιλέξτε τον ενικό αριθμό
Δημόσιος Κατάλογος www/
Αυτός ο κατάλογος είναι ο μόνος προσβάσιμος από τον ιστό (το λεγόμενο
document-root). Συχνά μπορείτε να συναντήσετε και το όνομα public/
αντί
για www/
– είναι απλώς θέμα σύμβασης και δεν επηρεάζει τη
λειτουργικότητα. Ο κατάλογος περιέχει:
- Το σημείο εισόδου της
εφαρμογής
index.php
- Το αρχείο
.htaccess
με κανόνες για το mod_rewrite (για τον Apache) - Στατικά αρχεία (CSS, JavaScript, εικόνες)
- Ανεβασμένα αρχεία
Για τη σωστή ασφάλεια της εφαρμογής, είναι ζωτικής σημασίας να έχετε σωστά διαμορφωμένο το document-root.
Ποτέ μην τοποθετείτε τον φάκελο node_modules/
σε αυτόν τον
κατάλογο – περιέχει χιλιάδες αρχεία που μπορεί να είναι εκτελέσιμα
και δεν θα πρέπει να είναι δημόσια προσβάσιμα.
Κατάλογος Εφαρμογής app/
Αυτός είναι ο κύριος κατάλογος με τον κώδικα της εφαρμογής. Η βασική δομή:
app/ ├── Core/ ← θέματα υποδομής ├── Model/ ← business λογική ├── Presentation/ ← presenters και templates ├── Tasks/ ← σενάρια εντολών └── Bootstrap.php ← κλάση εκκίνησης της εφαρμογής
Το Bootstrap.php
είναι η κλάση
εκκίνησης της εφαρμογής, η οποία αρχικοποιεί το περιβάλλον, φορτώνει
τη διαμόρφωση και δημιουργεί το DI container.
Ας ρίξουμε τώρα μια πιο λεπτομερή ματιά στους επιμέρους υποκαταλόγους.
Presenters και Πρότυπα
Το τμήμα παρουσίασης της εφαρμογής βρίσκεται στον κατάλογο
app/Presentation
. Μια εναλλακτική είναι το σύντομο app/UI
. Είναι ο
τόπος για όλους τους presenters, τα templates τους και τυχόν βοηθητικές
κλάσεις.
Οργανώνουμε αυτό το επίπεδο ανά τομείς. Σε ένα σύνθετο έργο που συνδυάζει e-shop, blog και API, η δομή θα έμοιαζε ως εξής:
app/Presentation/ ├── Shop/ ← e-shop frontend │ ├── Product/ │ ├── Cart/ │ └── Order/ ├── Blog/ ← blog │ ├── Home/ │ └── Post/ ├── Admin/ ← διαχείριση │ ├── Dashboard/ │ └── Products/ └── Api/ ← API endpoints └── V1/
Αντίθετα, για ένα απλό blog, θα χρησιμοποιούσαμε την εξής διάρθρωση:
app/Presentation/ ├── Front/ ← frontend webu │ ├── Home/ │ └── Post/ ├── Admin/ ← διαχείριση │ ├── Dashboard/ │ └── Posts/ ├── Error/ └── Export/ ← RSS, sitemaps κ.λπ.
Φάκελοι όπως Home/
ή Dashboard/
περιέχουν presenters και templates.
Φάκελοι όπως Front/
, Admin/
ή Api/
ονομάζονται modules.
Τεχνικά, πρόκειται για συνηθισμένους καταλόγους που χρησιμεύουν για
τη λογική διάρθρωση της εφαρμογής.
Κάθε φάκελος με presenter περιέχει έναν ομώνυμο presenter και τα templates του. Για
παράδειγμα, ο φάκελος Dashboard/
περιέχει:
Dashboard/ ├── DashboardPresenter.php ← presenter └── default.latte ← template
Αυτή η δομή καταλόγων αντικατοπτρίζεται στους χώρους ονομάτων των
κλάσεων. Για παράδειγμα, το DashboardPresenter
βρίσκεται στον χώρο
ονομάτων App\Presentation\Admin\Dashboard
(βλ. mapování
presenterů):
namespace App\Presentation\Admin\Dashboard;
class DashboardPresenter extends Nette\Application\UI\Presenter
{
// ...
}
Στον presenter Dashboard
μέσα στο module Admin
αναφερόμαστε στην
εφαρμογή χρησιμοποιώντας τη σημειογραφία με άνω και κάτω τελεία ως
Admin:Dashboard
. Στην action του default
στη συνέχεια ως
Admin:Dashboard:default
. Σε περίπτωση ένθετων modules, χρησιμοποιούμε
περισσότερες άνω και κάτω τελείες, για παράδειγμα
Shop:Order:Detail:default
.
Ευέλικτη Ανάπτυξη Δομής
Ένα από τα μεγάλα πλεονεκτήματα αυτής της δομής είναι το πόσο κομψά προσαρμόζεται στις αυξανόμενες ανάγκες του έργου. Ας πάρουμε ως παράδειγμα το τμήμα που δημιουργεί XML feeds. Στην αρχή, έχουμε μια απλή μορφή:
Export/ ├── ExportPresenter.php ← ένας presenter για όλες τις εξαγωγές ├── sitemap.latte ← template για το sitemap └── feed.latte ← template για το RSS feed
Με τον καιρό, προστίθενται περισσότεροι τύποι feeds και χρειαζόμαστε
περισσότερη λογική γι' αυτούς… Κανένα πρόβλημα! Ο φάκελος Export/
γίνεται απλά ένα module:
Export/ ├── Sitemap/ │ ├── SitemapPresenter.php │ └── sitemap.latte └── Feed/ ├── FeedPresenter.php ├── zbozi.latte ← feed για το Zboží.cz └── heureka.latte ← feed για το Heureka.cz
Αυτή η μετατροπή είναι απολύτως ομαλή – αρκεί να δημιουργήσετε
νέους υποφακέλους, να χωρίσετε τον κώδικα σε αυτούς και να ενημερώσετε
τους συνδέσμους (π.χ. από Export:feed
σε Export:Feed:zbozi
). Χάρη σε
αυτό, μπορούμε να επεκτείνουμε σταδιακά τη δομή ανάλογα με τις ανάγκες,
το επίπεδο ένθεσης δεν περιορίζεται με κανέναν τρόπο.
Αν, για παράδειγμα, στη διαχείριση έχετε πολλούς presenters που
σχετίζονται με τη διαχείριση παραγγελιών, όπως OrderDetail
,
OrderEdit
, OrderDispatch
κ.λπ., μπορείτε για καλύτερη οργάνωση σε
αυτό το σημείο να δημιουργήσετε ένα module (φάκελο) Order
, στο οποίο θα
βρίσκονται (οι φάκελοι για) οι presenters Detail
, Edit
, Dispatch
και άλλοι.
Τοποθέτηση Προτύπων
Στα προηγούμενα παραδείγματα, είδαμε ότι τα templates βρίσκονται απευθείας στον φάκελο με τον presenter:
Dashboard/ ├── DashboardPresenter.php ← presenter ├── DashboardTemplate.php ← προαιρετική κλάση για το template └── default.latte ← template
Αυτή η τοποθέτηση αποδεικνύεται στην πράξη η πιο βολική – έχετε όλα τα σχετικά αρχεία αμέσως πρόχειρα.
Εναλλακτικά, μπορείτε να τοποθετήσετε τα templates στον υποφάκελο
templates/
. Το Nette υποστηρίζει και τις δύο παραλλαγές. Μπορείτε ακόμη
και να τοποθετήσετε τα templates εντελώς εκτός του φακέλου Presentation/
.
Όλα σχετικά με τις δυνατότητες τοποθέτησης templates θα βρείτε στο
κεφάλαιο Αναζήτηση templates.
Βοηθητικές Κλάσεις και Components
Στους presenters και τα templates συχνά ανήκουν και άλλα βοηθητικά αρχεία. Τα τοποθετούμε λογικά ανάλογα με το πεδίο εφαρμογής τους:
1. Απευθείας στον presenter σε περίπτωση συγκεκριμένων components για τον συγκεκριμένο presenter:
Product/ ├── ProductPresenter.php ├── ProductGrid.php ← component για την εμφάνιση προϊόντων └── FilterForm.php ← φόρμα για φιλτράρισμα
2. Για το module – συνιστούμε να χρησιμοποιήσετε τον φάκελο
Accessory
, ο οποίος τοποθετείται βολικά στην αρχή της αλφαβήτου:
Front/ ├── Accessory/ │ ├── NavbarControl.php ← components για το frontend │ └── TemplateFilters.php ├── Product/ └── Cart/
3. Για ολόκληρη την εφαρμογή – στο Presentation/Accessory/
:
app/Presentation/ ├── Accessory/ │ ├── LatteExtension.php │ └── TemplateFilters.php ├── Front/ └── Admin/
Ή μπορείτε να τοποθετήσετε βοηθητικές κλάσεις όπως LatteExtension.php
ή TemplateFilters.php
στον φάκελο υποδομής app/Core/Latte/
. Και τα components
στο app/Components
. Η επιλογή εξαρτάται από τις συνήθειες της ομάδας.
Model – Η Καρδιά της Εφαρμογής
Το Model περιέχει όλη την business λογική της εφαρμογής. Για την οργάνωσή του ισχύει ξανά ο κανόνας – δομούμε ανά τομείς:
app/Model/ ├── Payment/ ← όλα γύρω από τις πληρωμές │ ├── PaymentFacade.php ← κύριο σημείο εισόδου │ ├── PaymentRepository.php │ ├── Payment.php ← entity ├── Order/ ← όλα γύρω από τις παραγγελίες │ ├── OrderFacade.php │ ├── OrderRepository.php │ ├── Order.php └── Shipping/ ← όλα γύρω από την αποστολή
Στο model, τυπικά συναντάμε αυτούς τους τύπους κλάσεων:
Facades: αντιπροσωπεύουν το κύριο σημείο εισόδου σε έναν συγκεκριμένο τομέα στην εφαρμογή. Λειτουργούν ως ενορχηστρωτής, που συντονίζει τη συνεργασία μεταξύ διαφόρων υπηρεσιών με σκοπό την υλοποίηση πλήρων use-cases (όπως “δημιουργία παραγγελίας” ή “επεξεργασία πληρωμής”). Κάτω από το επίπεδο ενορχήστρωσης, η facade κρύβει τις λεπτομέρειες υλοποίησης από την υπόλοιπη εφαρμογή, παρέχοντας έτσι μια καθαρή διεπαφή για την εργασία με τον συγκεκριμένο τομέα.
class OrderFacade
{
public function createOrder(Cart $cart): Order
{
// επικύρωση
// δημιουργία παραγγελίας
// αποστολή e-mail
// καταγραφή στα στατιστικά
}
}
Υπηρεσίες (Services): εστιάζουν σε μια συγκεκριμένη business λειτουργία εντός του τομέα. Σε αντίθεση με τη facade, η οποία ενορχηστρώνει ολόκληρα use-cases, μια υπηρεσία υλοποιεί συγκεκριμένη business λογική (όπως υπολογισμούς τιμών ή επεξεργασία πληρωμών). Οι υπηρεσίες είναι τυπικά stateless και μπορούν να χρησιμοποιηθούν είτε από facades ως δομικά στοιχεία για πιο σύνθετες λειτουργίες, είτε απευθείας από άλλα μέρη της εφαρμογής για απλούστερες εργασίες.
class PricingService
{
public function calculateTotal(Order $order): Money
{
// υπολογισμός τιμής
}
}
Repositories: εξασφαλίζουν όλη την επικοινωνία με τον χώρο αποθήκευσης δεδομένων, τυπικά μια βάση δεδομένων. Ο ρόλος του είναι η φόρτωση και η αποθήκευση entities και η υλοποίηση μεθόδων για την αναζήτησή τους. Το repository απομονώνει την υπόλοιπη εφαρμογή από τις λεπτομέρειες υλοποίησης της βάσης δεδομένων και παρέχει μια αντικειμενοστραφή διεπαφή για την εργασία με δεδομένα.
class OrderRepository
{
public function find(int $id): ?Order
{
}
public function findByCustomer(int $customerId): array
{
}
}
Entities: αντικείμενα που αντιπροσωπεύουν τις κύριες business έννοιες στην εφαρμογή, οι οποίες έχουν τη δική τους ταυτότητα και αλλάζουν με την πάροδο του χρόνου. Τυπικά, πρόκειται για κλάσεις που αντιστοιχίζονται σε πίνακες βάσης δεδομένων χρησιμοποιώντας ORM (όπως το Nette Database Explorer ή το Doctrine). Οι entities μπορούν να περιέχουν business κανόνες που σχετίζονται με τα δεδομένα τους και λογική επικύρωσης.
// Entity αντιστοιχισμένη στον πίνακα βάσης δεδομένων orders
class Order extends Nette\Database\Table\ActiveRow
{
public function addItem(Product $product, int $quantity): void
{
$this->related('order_items')->insert([
'product_id' => $product->id,
'quantity' => $quantity,
'unit_price' => $product->price,
]);
}
}
Value objects: αμετάβλητα αντικείμενα που αντιπροσωπεύουν τιμές χωρίς δική τους ταυτότητα – για παράδειγμα, ένα χρηματικό ποσό ή μια διεύθυνση e-mail. Δύο παρουσίες ενός value object με τις ίδιες τιμές θεωρούνται ταυτόσημες.
Κώδικας Υποδομής
Ο φάκελος Core/
(ή επίσης Infrastructure/
) είναι το σπίτι για την
τεχνική βάση της εφαρμογής. Ο κώδικας υποδομής τυπικά περιλαμβάνει:
app/Core/ ├── Router/ ← δρομολόγηση και διαχείριση URL │ └── RouterFactory.php ├── Security/ ← αυθεντικοποίηση και εξουσιοδότηση │ ├── Authenticator.php │ └── Authorizator.php ├── Logging/ ← καταγραφή και παρακολούθηση │ ├── SentryLogger.php │ └── FileLogger.php ├── Cache/ ← επίπεδο προσωρινής αποθήκευσης (caching) │ └── FullPageCache.php └── Integration/ ← ενσωμάτωση με εξωτερικές υπηρεσίες ├── Slack/ └── Stripe/
Για μικρότερα έργα, φυσικά, αρκεί μια επίπεδη διάρθρωση:
Core/ ├── RouterFactory.php ├── Authenticator.php └── QueueMailer.php
Πρόκειται για κώδικα που:
- Επιλύει την τεχνική υποδομή (δρομολόγηση, καταγραφή, caching)
- Ενσωματώνει εξωτερικές υπηρεσίες (Sentry, Elasticsearch, Redis)
- Παρέχει βασικές υπηρεσίες για ολόκληρη την εφαρμογή (mail, βάση δεδομένων)
- Είναι ως επί το πλείστον ανεξάρτητος από τον συγκεκριμένο τομέα – η cache ή ο logger λειτουργεί το ίδιο για eshop ή blog.
Αναρωτιέστε αν μια συγκεκριμένη κλάση ανήκει εδώ, ή στο model; Η βασική
διαφορά είναι ότι ο κώδικας στο Core/
:
- Δεν γνωρίζει τίποτα για τον τομέα (προϊόντα, παραγγελίες, άρθρα)
- Είναι ως επί το πλείστον δυνατό να μεταφερθεί σε άλλο έργο
- Επιλύει “πώς λειτουργεί” (πώς να στείλετε mail), όχι “τι κάνει” (ποιο mail να στείλετε)
Παράδειγμα για καλύτερη κατανόηση:
App\Core\MailerFactory
– δημιουργεί παρουσίες της κλάσης για την αποστολή e-mail, διαχειρίζεται τις ρυθμίσεις SMTPApp\Model\OrderMailer
– χρησιμοποιεί τοMailerFactory
για την αποστολή e-mail σχετικά με παραγγελίες, γνωρίζει τα templates τους και πότε πρέπει να σταλούν
Σενάρια Εντολών
Οι εφαρμογές συχνά χρειάζεται να εκτελούν δραστηριότητες εκτός των
συνηθισμένων HTTP requests – είτε πρόκειται για επεξεργασία δεδομένων στο
παρασκήνιο, συντήρηση, ή περιοδικές εργασίες. Για την εκτέλεση
χρησιμοποιούνται απλά σενάρια στον κατάλογο bin/
, ενώ η λογική
υλοποίησης τοποθετείται στο app/Tasks/
(ή app/Commands/
).
Παράδειγμα:
app/Tasks/ ├── Maintenance/ ← σενάρια συντήρησης │ ├── CleanupCommand.php ← διαγραφή παλιών δεδομένων │ └── DbOptimizeCommand.php ← βελτιστοποίηση βάσης δεδομένων ├── Integration/ ← ενσωμάτωση με εξωτερικά συστήματα │ ├── ImportProducts.php ← εισαγωγή από σύστημα προμηθευτή │ └── SyncOrders.php ← συγχρονισμός παραγγελιών └── Scheduled/ ← τακτικές εργασίες ├── NewsletterCommand.php ← αποστολή newsletter └── ReminderCommand.php ← ειδοποιήσεις πελατών
Τι ανήκει στο model και τι στα σενάρια εντολών; Για παράδειγμα, η λογική
για την αποστολή ενός e-mail είναι μέρος του model, η μαζική αποστολή
χιλιάδων e-mail ανήκει ήδη στο Tasks/
.
Οι εργασίες συνήθως εκκινούνται
από τη γραμμή εντολών ή μέσω cron. Μπορούν επίσης να εκκινηθούν μέσω HTTP
request, αλλά είναι απαραίτητο να σκεφτείτε την ασφάλεια. Ο presenter που
εκκινεί την εργασία πρέπει να ασφαλιστεί, για παράδειγμα, μόνο για
συνδεδεμένους χρήστες ή με ισχυρό token και πρόσβαση από επιτρεπόμενες
διευθύνσεις IP. Για μεγάλες εργασίες, είναι απαραίτητο να αυξήσετε το
χρονικό όριο του σεναρίου και να χρησιμοποιήσετε το
session_write_close()
, ώστε να μην κλειδώνεται η session.
Άλλοι Πιθανοί Κατάλογοι
Εκτός από τους βασικούς καταλόγους που αναφέρθηκαν, μπορείτε να προσθέσετε άλλους εξειδικευμένους φακέλους ανάλογα με τις ανάγκες του έργου. Ας ρίξουμε μια ματιά στους πιο συνηθισμένους από αυτούς και τη χρήση τους:
app/ ├── Api/ ← λογική για API ανεξάρτητη από το επίπεδο παρουσίασης ├── Database/ ← σενάρια μετανάστευσης και seeders για δοκιμαστικά δεδομένα ├── Components/ ← κοινόχρηστα οπτικά components σε ολόκληρη την εφαρμογή ├── Event/ ← χρήσιμο αν χρησιμοποιείτε event-driven αρχιτεκτονική ├── Mail/ ← e-mail templates και σχετική λογική └── Utils/ ← βοηθητικές κλάσεις
Για κοινόχρηστα οπτικά components που χρησιμοποιούνται σε presenters σε
ολόκληρη την εφαρμογή, μπορείτε να χρησιμοποιήσετε τον φάκελο
app/Components
ή app/Controls
:
app/Components/ ├── Form/ ← κοινόχρηστα components φόρμας │ ├── SignInForm.php │ └── UserForm.php ├── Grid/ ← components για λίστες δεδομένων │ └── DataGrid.php └── Navigation/ ← στοιχεία πλοήγησης ├── Breadcrumbs.php └── Menu.php
Εδώ ανήκουν τα components που έχουν πιο σύνθετη λογική. Αν θέλετε να μοιραστείτε components μεταξύ πολλών έργων, είναι σκόπιμο να τα διαχωρίσετε σε ένα ξεχωριστό composer πακέτο.
Στον κατάλογο app/Mail
μπορείτε να τοποθετήσετε τη διαχείριση της
επικοινωνίας μέσω e-mail:
app/Mail/ ├── templates/ ← e-mail templates │ ├── order-confirmation.latte │ └── welcome.latte └── OrderMailer.php
Αντιστοίχιση Presenters
Η αντιστοίχιση (mapping) ορίζει κανόνες για την εξαγωγή του ονόματος της
κλάσης από το όνομα του presenter. Τους καθορίζουμε στη διαμόρφωση κάτω από το κλειδί
application › mapping
.
Σε αυτή τη σελίδα, δείξαμε ότι τοποθετούμε τους presenters στον φάκελο
app/Presentation
(ή app/UI
). Πρέπει να ενημερώσουμε το Nette για αυτή τη
σύμβαση στο αρχείο διαμόρφωσης. Μια γραμμή αρκεί:
application:
mapping: App\Presentation\*\**Presenter
Πώς λειτουργεί η αντιστοίχιση; Για καλύτερη κατανόηση, ας
φανταστούμε πρώτα μια εφαρμογή χωρίς modules. Θέλουμε οι κλάσεις των presenters
να ανήκουν στον χώρο ονομάτων App\Presentation
, ώστε ο presenter Home
να
αντιστοιχεί στην κλάση App\Presentation\HomePresenter
. Αυτό το επιτυγχάνουμε
με αυτή τη διαμόρφωση:
application:
mapping: App\Presentation\*Presenter
Η αντιστοίχιση λειτουργεί έτσι ώστε το όνομα του presenter Home
να
αντικαθιστά τον αστερίσκο στη μάσκα App\Presentation\*Presenter
, δίνοντας το
τελικό όνομα κλάσης App\Presentation\HomePresenter
. Απλό!
Ωστόσο, όπως βλέπετε στα παραδείγματα σε αυτό και σε άλλα κεφάλαια,
τοποθετούμε τις κλάσεις των presenters σε ομώνυμους υποκαταλόγους, για
παράδειγμα, ο presenter Home
αντιστοιχεί στην κλάση
App\Presentation\Home\HomePresenter
. Αυτό το επιτυγχάνουμε διπλασιάζοντας την
άνω και κάτω τελεία (απαιτεί Nette Application 3.2):
application:
mapping: App\Presentation\**Presenter
Τώρα προχωράμε στην αντιστοίχιση presenters σε modules. Για κάθε module, μπορούμε να ορίσουμε μια συγκεκριμένη αντιστοίχιση:
application:
mapping:
Front: App\Presentation\Front\**Presenter
Admin: App\Presentation\Admin\**Presenter
Api: App\Api\*Presenter
Σύμφωνα με αυτή τη διαμόρφωση, ο presenter Front:Home
αντιστοιχεί στην
κλάση App\Presentation\Front\Home\HomePresenter
, ενώ ο presenter Api:OAuth
στην κλάση
App\Api\OAuthPresenter
.
Επειδή τα modules Front
και Admin
έχουν παρόμοιο τρόπο
αντιστοίχισης και πιθανότατα θα υπάρχουν περισσότερα τέτοια modules,
είναι δυνατό να δημιουργηθεί ένας γενικός κανόνας που τα αντικαθιστά.
Έτσι, στη μάσκα της κλάσης προστίθεται ένας νέος αστερίσκος για το
module:
application:
mapping:
*: App\Presentation\*\**Presenter
Api: App\Api\*Presenter
Λειτουργεί επίσης για βαθύτερα ένθετες δομές καταλόγων, όπως για
παράδειγμα ο presenter Admin:User:Edit
, με το τμήμα με τον αστερίσκο να
επαναλαμβάνεται για κάθε επίπεδο και το αποτέλεσμα να είναι η κλάση
App\Presentation\Admin\User\Edit\EditPresenter
.
Μια εναλλακτική σύνταξη είναι να χρησιμοποιήσετε έναν πίνακα που αποτελείται από τρία τμήματα αντί για μια συμβολοσειρά. Αυτή η σύνταξη είναι ισοδύναμη με την προηγούμενη:
application:
mapping:
*: [App\Presentation, *, **Presenter]
Api: [App\Api, '', *Presenter]