Anzeige
Anzeige

Más contenido relacionado

Anzeige
Anzeige

Zend Framework 2 - Best Practices

  1. Ralf Eggert | Travello GmbH Zend Framework 2 - Best Practices Quelle: DASPRiD / flickr
  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. 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. MVC Quelle: D. Braun / pixelio.de
  5. Model-View-Controller • Entwurfsmuster – Model: Business Logik – View: Präsentationslogik – Controller: Steuerungslogik • Warum MVC? – Übersichtlichkeit – Testbarkeit – Wartbarkeit • Paradigma – »Thin Controllers / Fat Models«
  6. Bestandteile einer ZF2 Anwendung • Entitäten • Hydratoren • Controller • Controller-Plugins • TableGateways • Formulare • InputFilter • Filter • Validatoren • View-Skripte • View-Helper
  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. Lösung: Model-Services einführen • Model-Services • Entitäten • Hydratoren • Controller • Controller-Plugins • TableGateways • Formulare • InputFilter • Filter • Validatoren • View-Skripte • View-Helper
  9. Better Practice: Controller & Model-Service ModelService Request Controller Formular Response View
  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. Better Practice: View mit Model-Service Controller View ViewSkripte Response ViewHelper nur lesend! Model Service
  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. Verschiedene Datenspeicher ZF2 TableGateway Doctrine ORM Controller ModelService Dateisystem REST SOAP XML-RPC
  14. Module Quelle: Carsten Jünger / pixelio.de
  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. 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. 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. 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. Fremdmodule • http://modules.zendframework.com/ • https://github.com/ZF-Commons • https://github.com/zfcampus • Beispiele: – ZfcUser / ZfcUser2 – DoctrineModule – DoctrineORMModule – ZendDeveloperTools – BjyProfiler
  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. Service-Manager Quelle: neurolle - Rolf / pixelio.de
  22. Service Locator • Service-Locator – Entwurfsmuster • Service-Manager – Konkrete Implementation • Aufgaben – Instanziierung von Objekten / Services – Bereitstellung der Instanzen zur Wiederverwendung
  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. 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. 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. 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. 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. Event-Manager Quelle: Rainer Sturm / pixelio.de
  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. 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. 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. 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. Formularverarbeitung Quelle: Matthias Preisinger / pixelio.de
  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. 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. 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. 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. Application-Management Quelle: Helene Souza / wikimedia
  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. 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. 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. 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. Performance Quelle: günther gumhold / pixelio.de
  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. 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. Security Quelle: piu700 / pixelio.de
  47. ZF2 Komponenten für Security • Authentifizierung / Autorisierung – ZendAuthentication – ZendPermissions – ZendCaptcha • »Filter Input, Escape Output« – ZendFilter – ZendValidator – ZendInputFilter – ZendEscaper • Sichere Zufallswerte – ZendMath
  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. Migration vom ZF1 Quelle: sokaeiko / pixelio.de
  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. 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. 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. Das ZF3 kommt demnächst in diesem Kino Quelle: DASPRiD / flickr
  54. Fragen?! Quelle: Tony Hegewald / pixelio.de
  55. Ralf Eggert | Travello GmbH Vielen Dank für Eure Aufmerksamkeit Quelle: DASPRiD / flickr
Anzeige