Das “CRUD-Pattern”, oder wie Konventionen das Leben einfacher machen können

| Keine Kommentare

Heute geht es wiedermal um eine alltägliche Aufgabe bei der Entwicklung von (Web-)Software: CRUD. Vielen wird es sicherlich ein Begriff sein, denn wir wenden es, wenn vielleicht auch nicht bewusst, jeden Tag an.

Dabei geht es um die verschiedenen Schritte, wie Daten bearbeitet werden können. CRUD ansich ist erstmal kein Designmuster im herkömmlichen Sinne, aber es lässt sich für verschiedene Arten von Datenmodellen eine immer wiederkehrendes Muster erkennen.

In vielen Projekten habe ich erlebt, dass für jedes Modell oder Entity mindestens ein Kontroller implementiert wurde, um die irgendwie manipulieren und anzeigen zu können.

Oftmals werden bekannte und gut geprüfte Frameworks eingesetzt, um die Arbeit zu erleichtern und einheitliche Standards zu nutzen.

Warum also nicht auch einfach hier fertige Module nutzen oder sollte es tatsächlich nichts fertiges geben, einfach gute eigene Basiskontroller verwenden?

Der Ausgangspunkt ist erstmal klar und einfach: CRUD, d.h. C – create (erzeugen), R – read (lesen/anzeigen), U – update (bearbeiten) und D – delete (löschen).

Damit haben wir schon unsere ersten Controller-Actions zusammen. Ich halte den Code allgemein wie möglich, da sich das auf sämtliche Frameworks übertragen lässt.

<?php
class CrudController {
  public function indexAction() {}
  public function viewAction() {}
  public function editAction() {}
  public function deleteAction() {}
}

Bei den Actions folge ich nicht ganz dem “CRUD-Muster”. Die Edit-Action vereint in diesem Beispiel “create” und “update”, da die dahinterstehende Logik oft fast identisch ist.

Kümmern wir uns doch aber erstmal um die einfachen Actions. Die index-Action soll uns eine Liste der verfügbaren Datensätze anzeigen.

Dafür laden wir eine Collection des jeweiligen Typs und rendern das passende Template. Wenn wir in der Benennung aller Klassen einer bestimmten Namenskonvention folgen, können wir z.B. vom Namen der Kontrollerklasse auf den des jeweiligen Models schließen.

class CrudController {
  public function indexAction() {
    $collection = $this->getCollection();
    return $this->render( $this->getListTemplate(), $collection );
  }
}

class UserController extend CrudController() {
}

Nach ähnlichem Muster würde dann auch die View-Action arbeiten. Den Namen des Templates leiten wir aus dem Klassennamen des Controllers ab. Das Wichtige und Interessante dabei ist natürlich, dass eigentlich alles im CrudController passiert und nicht immer wieder neu geschrieben werden soll. Die erbenden Controller geben dann nur noch ihren Namen her und passen hier und da etwas an.

class CrudController {
  public function viewAction($id) {
    $model = $this->getModel()->find($id);
    return $this->render( $this->getViewTemplate(), array('model' => $model) );
  }
}

Beim Löschen verhält es sich ähnlich einfach, nur dass hier noch ein weiterer Parameter gebraucht wird.

class CrudController {
  public function deleteAction($id, $confirm = false) {
    $model = $this->getModel()->find($id);

    if(!$confirm) {
      return $this->render( $this->getDeleteConfirmTemplate(), array('model' => $model) );
    }

    $model->delete();
    return $this->render( $this->getDeleteSuccessTemplate(), array('model' => $model) );
  }
}

Den meisten Aufwand haben wir beim Bearbeiten von Datensätzen.

class CrudController {
  public function editAction($id = false) {
    $request = $this->getRequest();
    $form = $this->getForm();

    // model bleibt leer, wenn nichts geladen werden kann
    $model = $this->getModel()->find($id);

    if($request->isPost()) {
      if($form->isValid( $request )) {
        $model->setData( $form->getData() );
        $model->save();
        $this->setFlashMsg( 'Speichern ok' );
        return $this->redirect( $this->getListUrl() );
      }
    }

    return $this->render( $this->getEditTemplate(), array('form' => $form) );
  }
}

Das Beispiel ist natürlich nicht komplett, soll aber zeigen, wieviel arbeit wir uns täglich sparen können und gleichzeitig durch einheitliche Standards ein flexibles und stabiles Produkt schaffen.

Hinterlasse eine Antwort

Pflichtfelder sind mit * markiert.


Schlagwörter: A/B-Test, AbstractType, Adapter, AddOn, Administration, Ajax, Amazon, Animation, Annotations, Anonyme Klasse, Ant, Apache, API, Array, ArrayAccess, Attachment, Auftrag, Ausbildung, Auswertung, Authentifizierung, AutoLoader, AWS, Bedienung, Bedingung, Benchmark, Berechtigung, Berlin, Bildbearbeitung, Bildschirmfoto, Blog, Blogroll, BOM, Bootstrap, Bot, Browser, Bugtracker, Byte Order Mark, Bücher, Cache, CakePHP, Call-Center, Callback, CamelCase, Canvas, Captcha, CDN, Cheatsheet, CLI, Clickout, Closure, Cloud, CodeSniffer, Collection, Community, Comparator, Config, Contest, Controller, Converter, CouchDB, Countable, Cronjob, CRUD, CSS, CSV, CustomLibrary, Custom_Model, Daemon, Data Mapper, Datei, Datenbank, Datenstruktur, Datentypen, Dating, Datum, Debug, Decorator, Dekorierer, Design, Design Patterns, Doctrine, Dokumentation, Dump, Duplikat, each, EC2, Eclipse, Email, Entwicklung, Entwurfsmuster, Enum, Erweiterung, Event, Eventhandling, Exception-Handling, Extension, Facebook, Factory, Fallback, Fehler, Fehlermeldung, Filter, Firefox, Flash, flexigrid, Foreach, Formatierung, Formular, Framework, FTP, Funktion, Futon, ga:pi(), Getter, Google Analytics, Hash, Hash-Bang, Header, htaccess, HTML5, htpasswd, HTTP, HTTPS, IDE, If, Implementierung, InnoDB, Interceptor, Interface, Internet Explorer, isset, Iterator, Java, JavaScript, Job, jQuery, Kommentar, Konfiguration, Konsole, Kontrollstruktur, kopieren, kostenlos, Kundenbetreuung, Late Static Binding, Layout, Links, Linux, Listeners, Lizenz, Logging, Löschen, Magento, Magic Methods, Manual, ManyToMany, Marketing, Methode, Model, Monolog, MVC, MySQL, NetBeans, Network, Nirvanix, Objekt, Observable, Observer, OneToMany, Online Tool, OOP, Open Source, Operator, OR-Mapper, Order, ORM, O’Reilly, Parameter, Partnersuche, Passwort, Performance, PHP, php.ini, PHP hates me, phpMyAdmin, PHPUnit, Plugin, Popup, Proxy, Prüfsumme, Prüfung, QR-Code, Qualitätssicherung, Query, Queue, Redesign, Refactoring, Reflection, Request, Response, Responsive Design, Rest-API, Rockstar, Rollback, Routing, S3, Samba, Scheifen, Schleife, Schutz, Screenshot, Secure Shell, Selbstreferenz, Server, Setter, setTimeout, Shop, Sicherheit, Sicherung, Sichtbarkeit, Singleton Pattern, Skin, SOAP, Social Network, Software, Sortierung, Sourcecode, Spam, Speicherproblem, Spickzettel, SPL, Splittest, SSH, SSL, Stammtisch, Statement, static, Statistik, Status, Stellvertreter, Strategy Pattern, Stream, String, Stuttgart, Stylesheet, Subversion, Sun VirtualBox, Support, SVN, Switch, Symfony, Symfony2, Symfony Live, Tag, Template, Template Method, Ternär Operator, Testing, Theme, Thumbnail, Tool, Tour, Tracking, Twig, Twitter, Type-Cast, Ubuntu, Umwandlung, Underscore, unset, Update, Upload, Url, User Story, Validierung, Vererbung, Versionskontrolle, Versionsnummer, Verzweigung, Video, Videospiel, Virtualisierung, Visitor Pattern, Vorschaubild, walk, Warteschlange, Webserver, Webservice, Weiterleitung, Werkzeug, Windows, WindowsAzure, WordPress, Wrapper, Writer, XML, Youtube, Zeitschleife, Zeitsteuerung, Zend Framework, Zend_Application, Zend_Cloud, Zend_CodeGenerator, Zend_Http_Client, Zend_Reflection, Zend_Service, ZPress, Zugangskontrolle, Zugriffsmethode