Zend Framework 2 - Best Practices

6,822 views
6,469 views

Published on

Erfahren Sie in diesem Talk, wie Sie das Zend Framework 2 gewinnbringend für Ihre eigenen Projekte einsetzen können. Sie erhalten Tipps aus der Praxis für die Praxis zu Themen wie Performance, Security, Wiederverwendbarkeit von Modulen, Einsatz des Event-Managers für eigene Zwecke, interessante Fremdmodule, Migration vom ZF1, und vieles mehr.

0 Comments
7 Likes
Statistics
Notes
  • Be the first to comment

No Downloads
Views
Total views
6,822
On SlideShare
0
From Embeds
0
Number of Embeds
116
Actions
Shares
0
Downloads
81
Comments
0
Likes
7
Embeds 0
No embeds

No notes for slide

Zend Framework 2 - Best Practices

  1. 1. Ralf Eggert | Travello GmbH Zend Framework 2 - Best Practices Quelle: DASPRiD / flickr
  2. 2. Über Ralf Eggert • Geschäftsführer Travello GmbH • Buchautor & Kolumnist – Zend Framework 1 (Addison-Wesley) – Zend Framework 2 (Galileo Computing) – PHP Magazin • Zend Framework seit 2006 • Contributor, Speaker, Trainer – http://www.ralfeggert.de/ – http://www.zendframeworkschulung.de/
  3. 3. Drei Fragen an das Publikum? • Wer – hat Erfahrungen mit dem Zend Framework 2? – entwickelt an einem Zend Framework 2 Projekt? – hat ein ZF2 Projekt im Live-Betrieb?
  4. 4. MVC Quelle: D. Braun / pixelio.de
  5. 5. Model-View-Controller • Entwurfsmuster – Model: Business Logik – View: Präsentationslogik – Controller: Steuerungslogik • Warum MVC? – Übersichtlichkeit – Testbarkeit – Wartbarkeit • Paradigma – »Thin Controllers / Fat Models«
  6. 6. Bestandteile einer ZF2 Anwendung • Entitäten • Hydratoren • Controller • Controller-Plugins • TableGateways • Formulare • InputFilter • Filter • Validatoren • View-Skripte • View-Helper
  7. 7. Bad Practice: MVC Filter Filter Filter Formular Input Filter Validator Request Validator Controller Validator Manuela Peter Datenbank Klaus Entität Response View ViewSkripte ViewHelper
  8. 8. Lösung: Model-Services einführen • Model-Services • Entitäten • Hydratoren • Controller • Controller-Plugins • TableGateways • Formulare • InputFilter • Filter • Validatoren • View-Skripte • View-Helper
  9. 9. Better Practice: Controller & Model-Service ModelService Request Controller Formular Response View
  10. 10. Better Practice: Model mit Model-Service Controller Manuela Filter Filter Peter Filter Klaus Entität Hydrator Model Service Input Filter Validator Validator Datenbank Validator
  11. 11. Better Practice: View mit Model-Service Controller View ViewSkripte Response ViewHelper nur lesend! Model Service
  12. 12. Vorteile einer sauberen Trennung • Alles hat seinen Platz • Model-Service verwendbar von – Webanwendung – Cron-Job – RESTful Webservice – Javascript-Anwendung • Datenvalidierung nicht an Formular gekoppelt
  13. 13. Verschiedene Datenspeicher ZF2 TableGateway Doctrine ORM Controller ModelService Dateisystem REST SOAP XML-RPC
  14. 14. Module Quelle: Carsten Jünger / pixelio.de
  15. 15. Zend Framework 2 Module • Anwendungsspezifische Module – Verzeichnis /module • Fremdmodule – Verzeichnis /vendor • Unternehmensmodule – Verzeichnis /corporate – Oder Unternehmensname, z.B. /travello • Module können aufeinander aufbauen • Module können andere erweitern
  16. 16. Abhängigkeiten von ZF2 Modulen I • Beispiel: Modul Application • Funktionen – Layout – Fehlerseiten – Module laden – Konfiguration (z.B. Navigation) • Zugriff für andere Module – Ergänzende Konfiguration z.B. für ZendNavigation • Zugriff auf andere Module – Widgets über View-Helper aufrufen
  17. 17. Abhängigkeiten von ZF2 Modulen II • Beispiel: Modul User • Funktionen – Registrierung – Authentifizierung – Autorisierung – Event-Listener • Zugriff für andere Module – View-Helper: userIsAllowed und userWidget – Controller-Plugin: userIsAllowed • Direkten Zugriff auf Services vermeiden
  18. 18. Wiederverwendbarkeit • Jedes Modul braucht eigene Routen • .dist Datei für Konfiguration – Für /config/autoload Verzeichnis • Generalisiertes Markup im View verwenden – Twitter Bootstrap – Eigene CSS Struktur • Abhängigkeiten zu anderen Modulen reduzieren • Anderen Module Zugriff ermöglichen – View-Helper – Controller Plugins
  19. 19. Fremdmodule • http://modules.zendframework.com/ • https://github.com/ZF-Commons • https://github.com/zfcampus • Beispiele: – ZfcUser / ZfcUser2 – DoctrineModule – DoctrineORMModule – ZendDeveloperTools – BjyProfiler
  20. 20. ZF2 Module - Best Practices • Modulkonfiguration cachen! – Achtung! Nur getConfig() wird gecached • Jedes Modul konfiguriert eigenes Routing – Vermeiden: Keine einzelne Route für alle Module • onBootstrap() und init() sparsam nutzen • Nicht überladen: module.config.php – Konfigurationsdaten für Schuhgrößen, Währungskurse, Bildgrößen, finnische Biermarken usw. auslagern • Unternehmensmodule wiederverwenden
  21. 21. Service-Manager Quelle: neurolle - Rolf / pixelio.de
  22. 22. Service Locator • Service-Locator – Entwurfsmuster • Service-Manager – Konkrete Implementation • Aufgaben – Instanziierung von Objekten / Services – Bereitstellung der Instanzen zur Wiederverwendung
  23. 23. Spezialisierte Service-Manager ServiceManager Controller Loader Route-Plugin Loader Controller-Plugin Manager Serializer-Adapter Manager View-Helper Manager Hydrator Manager Validator Manager Filter Manager Form-Element Manager Input-Filter Manager
  24. 24. Beispiel Factory (mit kleiner Unschärfe) // Datei /module/Customer/src/Customer/Form/CustomerFormFactory.php namespace CustomerForm; use ZendServiceManagerFactoryInterface; use ZendServiceManagerServiceLocatorInterface; class CustomerFormFactory implements FactoryInterface { public function createService(ServiceLocatorInterface $formElementManager) { $serviceLocator = $formElementManager->getServiceLocator(); $hydratorManager = $serviceLocator->get('HydratorManager'); $inputFilterManager = $serviceLocator->get('InputFilterManager'); $filter = $inputFilterManager->get('CustomerCustomerFilter'); $config = $inputFilterManager->getServiceLocator()->get('Config'); $form = new CustomerForm($config['country_options']); $form->setHydrator($hydratorManager->get('ArraySerializable')); $form->setInputFilter($filter); return $form; } }
  25. 25. Beispiel Factory (verbessert) // Datei /module/Customer/src/Customer/Form/CustomerFormFactory.php namespace CustomerForm; use ZendServiceManagerFactoryInterface; use ZendServiceManagerServiceLocatorInterface; class CustomerFormFactory implements FactoryInterface { public function createService(ServiceLocatorInterface $formElementManager) { $serviceLocator = $formElementManager->getServiceLocator(); $hydratorManager = $serviceLocator->get('HydratorManager'); $inputFilterManager = $serviceLocator->get('InputFilterManager'); $filter = $inputFilterManager->get('CustomerCustomerFilter'); $config = $serviceLocator->get('Config'); $form = new CustomerForm($config['country_options']); $form->setHydrator($hydratorManager->get('ArraySerializable')); $form->setInputFilter($filter); return $form; } }
  26. 26. Konfiguration (Auszug) // Datei /module/Customer/config/module.config.php return array( 'input_filters' => array( 'invokables' => array( 'CustomerCustomerFilter' ), 'shared' => array( 'CustomerCustomerFilter' ), ), => 'CustomerInputFilterCustomerFilter', => true, 'form_elements' => array( 'invokables' => array( 'CustomerAddressFieldset' => 'CustomerFormCustomerAddressFieldset', ), 'factories' => array( 'CustomerCustomerForm' => 'CustomerFormCustomerFormFactory', ), 'shared' => array( 'CustomerCustomerForm' => true, ), ), );
  27. 27. Service Manager - Best Practices • Spezialisierte Service-Manager nutzen • ServiceLocatorAwareInterface meiden • Service-Manager niemals injizieren! Nein, nie! • new möglichst nur in Factories verwenden • Initializer sparsam einsetzen • Abstract Factories sparsam einsetzen • Factory Closures in Konfigurationsdateien verhindern Caching • ZendServiceManager schneller als ZendDi
  28. 28. Event-Manager Quelle: Rainer Sturm / pixelio.de
  29. 29. Event-Manager im MVC • MVC Events – »bootstrap« – »route« – »dispatch« / »dispatch.error« – »render« / »render.error« – »finish« • Mvc Events für eigene Zwecke verwenden – Nach »route« Event Sprache der Anwendung festlegen – Nach »dispatch.error« Event Fehlermeldungen loggen – Vor »finish« Event HTML aufräumen / minifizieren
  30. 30. Event-Manager im Model-Service // Datei /module/Order/src/Order/Service/OrderService.php namespace OrderService; use ZendEventManagerEventManagerInterface; use ZendDebugDebug; class OrderService { protected $eventManager; public function setEventManager(EventManagerInterface $eventManager) { $eventManager->setIdentifiers(array(__CLASS__); $this->eventManager = $eventManager; } public function getEventManager() { return $this->eventManager; } public function saveOrder($id) { $this->getEventManager()->trigger('preOrder', __CLASS__, array('id' => $id)); Debug::dump('Save order ' . $id); $this->getEventManager()->trigger('postOrder', __CLASS__, array('id' => $id)); } }
  31. 31. Event-Manager konfigurieren use ZendDebugDebug; use ZendEventManagerEventManager; use OrderServiceOrderService; $eventManager = new EventManager(); $eventManager->attach('postOrder', function ($e) { Debug::dump('Update stock'); }, 100); $eventManager->attach('postOrder', function ($e) { Debug::dump('Send order confirmation'); }, 300); $eventManager->attach('preOrder', function ($e) { Debug::dump('Check stock'); }); $orderService = new OrderService(); $orderService->setEventManager($eventManager); $orderService->saveOrder('12345'); // output string 'Check stock' (length=11) string 'Save order 12345' (length=16) string 'Send order confirmation' (length=23) string 'Update stock' (length=12)
  32. 32. Event Manager - Best Practices • Eindeutige Identifier verwenden (Klassenname) • SharedEventManager – Fallback für alle Event-Manager Instanzen – Events für nicht existente Objekte registrieren • EventManagerAwareInterface • Listener – Aggregat-Klassen (ListenerAggregateInterface) – Closures
  33. 33. Formularverarbeitung Quelle: Matthias Preisinger / pixelio.de
  34. 34. Formularverarbeitung • InputFilter – ZendInputFilterInputFilter erweitern – Input-Elemente in init() per Factory hinzufügen – Hierarchische InputFilter möglich • Formulare – ZendFormForm erweitern – Formularelemente in init() per Factory hinzufügen – Hierarchie durch Fieldsets umsetzbar
  35. 35. Konfiguration Filter & Validatoren // Datei /module/Customer/config/module.config.php return array( 'filters' => array( 'invokables' => array( 'CustomerAddress' => 'CustomerFilterAddressFilter', ), ), 'validators' => array( 'invokables' => array( 'CustomerCountry' => 'CustomerValidatorCountryValidator', ), ), );
  36. 36. Beispiel InputFilter // Datei /module/Customer/src/Customer/InputFilter/CustomerFilter.php namespace CustomerInputFilter; use ZendInputFilterInputFilter; class CustomerFilter extends InputFilter { public function init() { $this->add(array( 'name' => 'address', 'filters' => array( array('name' => 'CustomerAddress'), ), )); $this->add(array( 'name' => 'country', 'validators' => array( array('name' => 'CustomerCountry'), ), )); } }
  37. 37. Formularverarbeitung - Best Practices • Validierung und Formularanzeige trennen – Im Model-Service mit InputFilter validieren – Im Controller Formular bereitstellen • Controller – Plugin PostRedirectGet – Plugin FilePostRedirectGet • Spezialisierte Service-Manager verwenden
  38. 38. Application-Management Quelle: Helene Souza / wikimedia
  39. 39. Application-Management • Management des Lebenszyklus der Anwendung • Mehrere Stufen (DTAP) – Development – Testing – Acceptance – Production • Weiche in /public/index.php • Pro Stufe eigene Konfiguration
  40. 40. Application-Management Weiche // Datei /public/index.php define('APPLICATION_ENV', (getenv('APPLICATION_ENV') ? getenv('APPLICATION_ENV') : 'production')); define('APPLICATION_ROOT', realpath(__DIR__ . '/..')); require_once '../vendor/autoload.php'; chdir(dirname(__DIR__)); switch (APPLICATION_ENV) { case 'production': $configFile = APPLICATION_ROOT . '/config/production.config.php'; break; case 'development': default: $configFile = APPLICATION_ROOT . '/config/development.config.php'; break; } ZendMvcApplication::init(include $configFile)->run();
  41. 41. Development Konfiguration // Datei /config/development.config.php return array( 'modules' => array( 'Application', 'User', 'Cms', 'Blog', 'ZendDeveloperTools', ), 'module_listener_options' => array( 'config_glob_paths' => array( 'config/autoload/{,*.}{production,development,local}.php', ), 'module_paths' => array( './module', './vendor', ), ), );
  42. 42. Production Konfiguration // Datei /config/production.config.php return array( 'modules' => array( 'Application', 'User', 'Cms', ), 'module_listener_options' => array( 'config_glob_paths' => array( 'config/autoload/{,*.}{production}.php', ), 'module_paths' => array( './module', './vendor', ), 'cache_dir' => './data/cache', 'config_cache_enabled' => false, 'config_cache_key' => 'module_config_cache', 'module_map_cache_enabled' => false, 'module_map_cache_key' => 'module_map_cache', ), );
  43. 43. Performance Quelle: günther gumhold / pixelio.de
  44. 44. ZF2 Performance • Modulkonfiguration cachen – Closures nicht cachebar – Achtung: Nur getConfig() wird gecached • ClassMaps und TemplateMaps einsetzen – Generator Skripte in /vendor/bin • Möglichst wenige parallele Routen • Fremdmodule – EdpSuperluminal – SpiffyNavigation – OcraCachedViewResolver
  45. 45. Performancebremsen • Größte Performancebremsen in Anwendung – Ineffiziente Datenbankabfragen – Nicht performante Berechnungen – Gelesene Daten werden nicht gecached • Generell – Einsatz eines Frameworks immer langsamer als prozedurale Skripte • Tipp – Eigenen Suchindex aufbauen
  46. 46. Security Quelle: piu700 / pixelio.de
  47. 47. ZF2 Komponenten für Security • Authentifizierung / Autorisierung – ZendAuthentication – ZendPermissions – ZendCaptcha • »Filter Input, Escape Output« – ZendFilter – ZendValidator – ZendInputFilter – ZendEscaper • Sichere Zufallswerte – ZendMath
  48. 48. Einsatzzwecke • Passwörter verschlüsseln – MD5 Hashes sind nicht sicher! – ZendCryptPasswordBcrypt • XSS vermeiden – Daten filtern und escapen • SQL Injection vermeiden – Mit ZendDbSql sicherer implementieren • Cross Site Request Forgery – ZendFormElementCsrf einsetzen
  49. 49. Migration vom ZF1 Quelle: sokaeiko / pixelio.de
  50. 50. Probleme bei Migration vom ZF1 • Kein Tool für automatische Migration • Kein Migration Layer • Migration-Guide in ZF2 Doku unvollständig • ZF1 bietet viele Freiheiten & verlangt keine 100% feste Struktur wie andere Frameworks • Allgemeingültige Schritt-für-Schritt-Anleitung für alle Anwendungen schwer umsetzbar • Kein ZF-spezifisches Problem
  51. 51. Migration ZF1 nach ZF2 • ZF1 und ZF2 parallel betreiben • Weiche in .htaccess einrichten • ZF2 Module müssen ZF1 Routing beachten • Modul für Modul migrieren • »Fat Models« leichter migrierbar • »Fat Controller« schwerer migrierbar • Weitere Quellen – Artikel im PHP Magazin 6/2013 (Teil 1) – IPC Spring Session: http://goo.gl/dgl8zH
  52. 52. Weiche in .htaccess // Datei /public/.htaccess RewriteEngine on # Slash am Ende entfernen RewriteRule ^(.+)/$ http://%{HTTP_HOST}/$1 [R=301,L] # Umschreiberegeln für ZF2 RewriteCond %{REQUEST_FILENAME} !-f RewriteRule ^$ index.zf2.php RewriteRule ^customer(.*)$ index.zf2.php RewriteRule ^order(.*)$ index.zf2.php RewriteRule ^cms(.*)$ index.zf2.php # Umschreiberegeln für ZF1 RewriteCond %{REQUEST_FILENAME} !-f RewriteRule .* index.zf1.php
  53. 53. Das ZF3 kommt demnächst in diesem Kino Quelle: DASPRiD / flickr
  54. 54. Fragen?! Quelle: Tony Hegewald / pixelio.de
  55. 55. Ralf Eggert | Travello GmbH Vielen Dank für Eure Aufmerksamkeit Quelle: DASPRiD / flickr

×