Zend Framework Tutorial Teil 11: Nützliche Komponenten Zend_Log und Zend_Mail

Im zehnten Teil vom Zend Framework Tutorial haben wir die Zend_Cache Komponente für das Cachen von Templates und Datenbankabfragen kennen gelernt und in unser Projekt integriert. Wenn du die ersten zehn Teile noch nicht gelesen hast, hole dies bitte schnell nach.

In diesem elften Teil des Zend Framework Tutorials werde ich gleich zwei Komponenten vorstellen. Mit Hilfe von Zend_Mail kannst du auf einfache Weise E-Mails erstellen und versenden und die Komponente Zend_Log ist für das individuelle Erstellen von Logs zuständig.

Wenn du über neue Tutorial Teile informiert werden möchtest, abonniere am besten den Feed dieses Blogs. Dann verpasst du garantiert keinen Teil des Tutorials.

Wichtig: Dieses Tutorial setzt die Zend Framework Preview Version 0.2.0 voraus und kann bei der Verwendung einer aktuelleren Version aus dem SVN unter Umständen nicht zu 100% funktionieren.

Inhaltsverzeichnis

Zend_Mail

Für den ersten Einblick in die Zend_Mail Komponente empfehle ich wie immer natürlich den Blick in das Zend_Mail Kapitel im Zend Framework Manual. Dort erfährst du neben der Funktionsweise des einfachen Versands und dem Versand per SMTP auch alles Wissenswerte über HTML E-Mail, Mailanhänge, das Setzen von zusätzlichen Headern und weiteren Empfängern sowie MIME-Abgrenzung und Zeichensätzen.

Hinweis

Bisher ist die Zend_Mail Komponente nur für den Versand von E-Mails zuständig. An einer Erweiterung auch für den Empfang von E-Mails wird aber bereits gearbeitet.

Die grundlegende Funktionsweise ist recht simpel und leicht zu durchschauen. Hier ein erstes Beispiel (entnommen aus dem Manual):

PHP:
  1. <?php
  2. require_once 'Zend/Mail.php';
  3. $mail = new Zend_Mail();
  4. $mail->setBodyText('Dies ist der Text dieser E-Mail.');
  5. $mail->setFrom('somebody@example.com', 'Ein Versender');
  6. $mail->addTo('somebody_else@example.com', 'Ein Empfänger');
  7. $mail->setSubject('TestBetreff');
  8. $mail->send();
  9. ?>

Die Methoden zum Setzen des Textes, des Absenders, des Empfängers und des Betreffs sind leicht nachzuvollziehen. Der Versand erfolgt hierbei über die normale mail() Funktion von PHP.

Für den Versand von E-Mails per SMTP müssen vor dem Erstellen des Zend_Mail Objektes noch folgende Zeilen eingefügt werden (am besten in der Bootstrap Datei oder, in unserem Falle, in der "settings.php" Datei):

PHP:
  1. $tr = new Zend_Mail_Transport_Smtp('mail.example.com');
  2. Zend_Mail::setDefaultTransport($tr);

Leider ist es derzeit noch nicht möglich, E-Mail mit SMTP Authentifizierung zu versenden. Wer dies dringend benötigt, sollte sich einmal diesen Patch anschauen, der hoffentlich bald implementiert wird.

Wichtiger Hinweis

Da die Einrichtung eines Mailservers unter Windows XP den Rahmen dieses Tutorials sprengen würde, gehe ich darauf nicht weiter ein. D.h. wenn du Zend_Mail so verwendest, wie hier angegeben, ist es wahrscheinlich, dass keine Mails versendet werden und du somit das Gefühl bekommst, dass Zend_Mail nicht funktioniert. Ich empfehle daher, das Projekt auf einem Server einzurichten, auf dem Mailversand möglich ist

Vorüberlegungen für Zend_Mail

Die sinnvollste Möglichkeit für den Versand einer E-Mail sind nach dem Schreiben eines neuen Kommentars oder nach dem Schreiben eines neuen Artikels. Nach diesen Aktionen könnte sich der Administrator des TravelloBlogs per E-Mail informieren lassen.

Es macht durchaus Sinn, die Standard Empfänger- und Versandadressen für diese E-Mails an einer zentralen Stelle zu speichern. Dafür bietet sich natürlich unsere "settings.ini" Datei im Verzeichnis "/application/config" an:

mail.defaultsender    = travelloblog@my-project.com
mail.defaultrecipient = admin@my-project.com

Da wir für unser Beispiel den normalen Versand und nicht den Versand per SMTP verwenden möchten, sind keine weiteren Arbeiten erforderlich. Falls du doch den SMTP Versand bevorzugst, kannst du in der "settings.php" noch folgende Zeilen hinzufügen:

PHP:
  1. $tr = new Zend_Mail_Transport_Smtp($config->mail->defaultsender);
  2. Zend_Mail::setDefaultTransport($tr);

Wie schon erwähnt, ist aber derzeit ein Versand mit SMTP Authentifizierung noch nicht möglich.

CommentController anpassen

Wir möchten uns als erstes per E-Mail über neue Kommentare informieren lassen. Es liegt also nahe, den Versand der E-Mail nach dem Speichern des neuen Kommentars durchführen zu lassen. Das wäre also somit in der Methode saveData im CommentController. Um diese Methode nicht zu unübersichtlich werden zu lassen, führen wir als erste eine neue private Methode sendMail im CommentController ein:

PHP:
  1. <?php
  2.     [...]
  3.  
  4.     private function sendMail($data)
  5.     {
  6.         $config = Zend::registry('config');
  7.        
  8.         $mailView = new Zend_View();
  9.         $mailView->setScriptPath($config->framework->view_dir);
  10.         $mailView->assign('comment', $data);
  11.        
  12.         $bodyText = $mailView->render('mail/new_comment.php');
  13.        
  14.         $mail = new Zend_Mail();
  15.         $mail->setBodyText($bodyText);
  16.         $mail->setFrom($config->mail->defaultsender);
  17.         $mail->addTo($config->mail->defaultrecipient);
  18.         $mail->setSubject('New comment');
  19.        
  20. //        $mail->send();
  21.     }
  22.  
  23.     [...]
  24. ?>

Was passiert hier? Zuerst holen wir unser Zend_Config Objekt aus dem Objektspeicher. Für das Erstellen des Mailtextesverwenden wir eine neuen Instanz von Zend_View. Das ist einfacher, als per PHP den Mailtext in einem String zusammen zu basteln. Wenn wir den Mailtext erstellt haben, können wir unser Zend_Mail Objekt erstellen und die verschiedenen Elemente mit Inhalten versehen.

Das abschließende Senden der E-Mail habe ich bewusst auskommentiert. Wenn auf deinem Entwicklungsrechner kein Mailserver installiert ist, bekommst du sonst entsprechende Fehlermeldung. Wenn du aber einen Mailserver verfügbar hast (was unter Unix / Linux wohl der Fall aus, aber damit kenne ich mich nicht besonders aus), dann kannst du die Zeile natürlich wieder einkommentieren.

Damit das aber funktionieren kann, benötigen wir noch zwei Dinge. Zum einen müssen wir in der Methode saveData im CommentController noch die Methode sendMail aufrufen:

PHP:
  1. <?php
  2.     [...]
  3.  
  4.     private function saveData($data)
  5.     {
  6.         [...]
  7.        
  8.         if (isset($data['com_id']))
  9.         {
  10.             [...]
  11.         }
  12.         else
  13.         {
  14.             $data['com_date'] = date('Y-m-d H:i:s');
  15.            
  16.             $com_id = $comment->insert($data);
  17.            
  18.             $data['com_id'] = $com_id;
  19.            
  20.             $this->sendMail($data);
  21.            
  22.             $art_id = $data['com_art_id'];
  23.         }
  24.        
  25.         [...]
  26.     }
  27.  
  28.     [...]
  29. ?>

Achte bitte darauf, dass du vor dem Aufruf von sendMail() noch die ID des neuen Kommentars an das Array $data übergibst.

Als nächstes brauchst du noch das Template "new_comment.php", welches du im Verzeichnis "/application/views/mail" anlegst:

PHP:
  1. A new comment was saved in the TravelloBlog. Here are the details:
  2. ==================================================================
  3.  
  4. <?php echo $this->escape($this->comment['com_title']) . "\n"; ?>
  5. <?php echo str_pad('-', strlen($this->comment['com_title']), '-') . "\n"; ?>
  6.  
  7. From    : <?php echo (strlen($this->comment['com_nickname'])> 0) ? $this->escape($this->comment['com_nickname']) : "anonymous"; ?>
  8. E-Mail  : <?php echo (strlen($this->comment['com_mail'])> 0) ? $this->escape($this->comment['com_mail']) : "-"; ?>
  9. Homepage: <?php echo (strlen($this->comment['com_homepage'])> 0) ? $this->escape($this->comment['com_homepage']) : "-"; ?>
  10. Date    : <?php echo $this->escape($this->comment['com_date']); ?>
  11.  
  12. Comment:
  13. <?php echo wordwrap($this->escape($this->comment['com_text']), 66, "\n"); ?>
  14.  
  15. ==================================================================
  16. Change: http://travelloblog/comment/change/<?php echo $this->escape($this->comment['com_id']); ?>
  17. Delete: http://travelloblog/comment/delete/<?php echo $this->escape($this->comment['com_id']); ?>
  18. ==================================================================

Die Ausgabe kannst du natürlich nach deinen Wünschen umstricken, aber ich denke, das Prinzip sollte klar sein. Du verwendest halt ein ganz normales PHP Skript für die Erstellung des Mailtextes, welches dann von Zend_View aufgerufen und verarbeitet wird.

Übung 1: Zend_Mail für neue Artikel

Als erste Übung bitte ich dich, auch für neue Artikel eine neue Mail zu versenden. Dafür benötigst du neben dem Mailtemplate natürlich auch wieder eine Funktion zum Versenden der Mail und musst den Versand in die entsprechende Methode im ArticleController aufrufen.

Natürlich kannst du dir auch noch weitere Aktionen überlegen, nach dem du eine Mail versenden möchtest. Dies wäre z.B. auch nach dem Anlegen von Kategorien oder Tags bzw. nach dem Ändern oder Löschen von Artikeln und Kommentaren denkbar.

Zur Kontrolle lade dir den aktuellen Stand des Tutorials runter. Dann kannst du deine Ergebnisse damit vergleichen.

Zend_Log

Auch für die Komponente Zend_Log empfehle ich zuerst den Blick in das entsprechende Kapitel im Zend Framework Manual Dies ist zwar noch recht knapp gehalten, beinhaltet aber schon alle wesentlichen Informationen.

Zend_Log kann im Gegensatz zu den meisten anderen Komponenten des Zend Frameworks nicht direkt instanziert werden. Über statische Aufrufe können aber verschiedene, auch mehrfache Logdateien erstellt werden. Dabei stehen mehrere Adapter für das Speichern der Logdaten in Dateien, in einer Datenbank oder in der Konsole zur Verfügung.

Die Verwendung ist recht einfach. Zuerst muss ein zu erstellendes Log unter Angabe des Adapters registriert werden. Danach kann über eine statische Methode überall, wo es notwendig erscheint, geloggt werden, was das Zeug hält. Dieses Beispiel aus dem Manual verwendet den Datei Adapter:

PHP:
  1. // Dateilog registrieren
  2. Zend_Log::registerLogger(new Zend_Log_Adapter_File('/logs/simple.txt'));
  3.  
  4. // einfache Nachricht registrieren
  5. Zend_Log::log('Erste Protokollnachricht.');
  6.  
  7. // schwerwiegenden Fehler registrieren
  8. Zend_Log::log('Ein schwerer Fehler ist aufgetreten.', Zend_Log::LEVEL_SEVERE);

Es lassen sich auch mehrere unabhängige Logs erstellen. Dann wird beim Aufruf von Zend_Log::registerLogger noch ein Name übergeben. Und beim Aufruf von Zend_Log::log muss dieser Name ebenfalls angegeben werden:

PHP:
  1. // zwei Logs erstellen
  2. Zend_Log::registerLogger(new Zend_Log_Adapter_File('/logs/framework.txt'), 'Datei');
  3. Zend_Log::registerLogger(new Zend_Log_Adapter_Console(), 'Konsole');
  4.  
  5. // Fehler im Dateilog aufnehmen
  6. Zend_Log::log('Ein schwerer Fehler ist aufgetreten.', Zend_Log::LEVEL_SEVERE, 'Datei');
  7.  
  8. // Fehler im Konsolenlog aufnehmen
  9. Zend_Log::log('Ein schwerer Fehler ist aufgetreten.', Zend_Log::LEVEL_SEVERE, 'Konsole');

Hierbei musst du aber darauf achten, dass du immer eine der möglichen Protokollstufen als zweiten Parameter angibst. Eine Übersicht über die Protokollstufen findest du im Manual.

Vorüberlegung für Zend_Log

Im Gegensatz zu Zend_Mail müssen wir für die Registrierung unseres Logs wieder die "settings.php" Datei bemühen, weil wir dort an zentraler Stelle das Log registrieren können.

Welche Informationen wirklich loggenswert sind, darüber gehen die Meinung weit auseinander. Wichtig ist es z.B. Fehler in einem zentralen Log zu speichern, das der Entwickler bei Bedarf dann genau untersuchen kann.

Da wir uns in unserem Projekt bisher jedoch noch nicht intensiv mit dieser Thematik befasst haben, möchte ich vorschlagen, dass wir alle Änderungen an der Datenbank zentral in einer Datei speichern. Also registrieren wir unser Datenbank Log als erstes am Ende unserer "settings.php" Datei:

PHP:
  1. Zend_Log::registerLogger(new Zend_Log_Adapter_File($config->framework->log_dir .'/database.txt'), 'Database');

Natürlich müssen wir dieses neue Verzeichnis auch noch anlegen und in unsere "settings.ini" Datei deklarieren:

framework.log_dir         = /path/to/travelloblog/logs

bzw.

framework.log_dir         = e:\travelloblog\logs

Damit kein Unbefugter auf die Logs zugreifen kann, müssen wir diesen Zugriff über den Webserver einschränken. Dafür brauchst du einfach nur die Datei ".htaccess" aus dem Verzeichnis "/application" in das neue Verzeichnis "/log" kopieren. Das war es dann an Vorbereitungen.

Datenbankänderungen loggen

Wir beginnen damit, die Datenbankänderungen für unsere Artikel zu loggen. Dafür öffne bitte die ArticleController Datei und suche die saveData Methode. Dort fügst du direkt hinter den Schreibzugriffen auf die Datenbank die Zeile für das Loggen der Aktion ein:

PHP:
  1. <?php
  2.     private function saveData($data)
  3.     {
  4.         [...]
  5.        
  6.         if (isset($data['art_id']))
  7.         {
  8.             [...]
  9.            
  10.             $row->save();
  11.  
  12.             Zend_Log::log('Article ' . $art_id . ' updated', Zend_Log::LEVEL_INFO, 'Database');
  13.         }
  14.         else
  15.         {
  16.             [...]
  17.            
  18.             $art_id = $article->insert($insertData);
  19.            
  20.             Zend_Log::log('Article ' . $art_id . ' created', Zend_Log::LEVEL_INFO, 'Database');
  21.            
  22.             [...]
  23.         }
  24.  
  25.         [...]
  26.     }
  27. ?>

In der doDeleteAction Methode stellst du dann noch sicher, dass auch das Löschen von Artikel geloggt wird:

PHP:
  1. <?php
  2.     public function doDeleteAction()
  3.     {
  4.         [...]
  5.        
  6.         $article->delete($where);
  7.        
  8.         Zend_Log::log('Article ' . $art_id . ' deleted', Zend_Log::LEVEL_INFO, 'Database');
  9.        
  10.         [...]
  11.     }
  12. ?>

Jetzt rufe einmal das TravelloBlog in deinem Browser auf und ändere ein paar Artikel, erstelle einen neuen Artikel oder lösche einen bestehenden. Dein Log sollte dann in etwas so aussehen.

Article 3 updated, INFO
Article 3 updated, INFO
Article 2 updated, INFO
Article 8 created, INFO
Article 8 deleted, INFO

Das war es auch schon. Dir steht mit Zend_Log auf jeden Fall eine gute Möglichkeit bereit, individuelle Logs für dein Projekt einzurichten und zu verwalten. Zum Beispiel wäre es noch denkbar, auch einen Zeitstempel mit zu loggen oder beim Loggen sehr schwerwiegender Fehler zeitgleich eine E-Mail an dem Administrator zu versenden. Der Fantasie sind da fast keine Grenzen gesetzt.

Übung 2: Zend_Log für Kommentare, Tags und Kategorien

Als zweite Übung bitte ich dich, auch für Kommentare, Tags und Kategorien entsprechende Meldungen in das Log zu schreiben. Wenn du möchtest, kannst du für jede Entität auch ein eigenes Log erstellen. Du kannst aber auch alle Datenbankänderungen zentral in einem Datenbanklog speichern.

Zur Kontrolle lade dir den aktuellen Stand des Tutorials runter. Dann kannst du deine Ergebnisse damit vergleichen.

Download

Der aktuelle Stand des Tutorials nach diesem sechsten Teil kann herunter geladen werden. Hier sind auch alle Templates enthalten. Die Textdateien "empty.txt" in einigen Verzeichnissen habe ich nur angelegt, weil mein Winzip keine leeren Verzeichnisse im Zip Archiv anlegt:

Die Zip Datei enthält nicht die aktuelle Version des Zend Frameworks. Dies musst du bitte selber in das entsprechende Verzeichnis kopieren.

Zusammenfassung

In diesem elften Teil des Zend Framework Tutorials haben wir die beiden nützlichen Komponenten Zend_Mail für das Versenden von E-Mails und Zend_Log für das Loggen von Informationen kennen gelernt. Auch wenn Windows Nutzer die Funktionsweise von Zend_Mail auf ihrem lokalen Entwicklungsrechner evtl. nicht zu 100% testen konnten, hoffe ich, dass das Prinzip jedoch klar geworden ist.

Nach diesem etwas kürzeren Kapitel kommen wir im nächsten Teil des Zend Framework Tutorials zu einem sehr spannenden Thema: das Versenden und Empfangen von Trackbacks mit Hilfe von Zend_Http_Client.

Change Log

An dieser Stelle werden Änderungen an diesem Tutorial Teil zusammengefasst, die nach dem Ersterscheinen (30.10.2006) notwendig waren, z.B. durch neuere Versionen des Zend Frameworks oder Änderungen am Konzept des Tutorials oder den Anforderungen an unser TravelloBlog.

  • 05.11.2006: Tutorial für Release 0.2.0 aktualisiert

Navigation

15 Antworten für “Zend Framework Tutorial Teil 11: Nützliche Komponenten Zend_Log und Zend_Mail”

  1. Uwe Wagner sagt:

    Hallo,

    ist es möglich, daß dieses sehr nützliche Tutorial an das heute herausgekommene ZF 0.20 angepaßt wird.

    Grüße
    Uwe Wagner

  2. Ralf Eggert sagt:

    Hallo Uwe,

    es ist schon geplant, das Tutorial an neue Release anzupassen. Nur dauert das natürlich immer so seine Zeit. Also bitte noch ein wenig Geduld.

    Gruß,

    Ralf

  3. Thomas Peterson sagt:

    Hey

    Ich freue mich schon auf das Trackback Tutorial.

    Wie siehts eigendlich mit euerem Form Projekt aus in Zend?

    Und weist du ob es in Zend auch ein ORM Tool integriert wird?

    MFG

  4. Ralf Eggert sagt:

    Hallo Thomas,

    das Trackback Tutorial muss ich leider verschieben. Erst einmal muss ich die Änderungen von Release 0.2 einarbeiten. Montag gibt es eine Sonderausgabe für das Upgrade.

    Beim Form Projekt konnte ich letzte Zeit wenig mitarbeiten. Es geht aber langsam voran. Ein ORM Tool ist irgendwie geplant, bisher wird es aber nur diskutiert. Kommt sicher früher oder später...

    Gruß,

    Ralf

  5. Ralfs PHP Blog » Zend Framework Tutorial Teil 1: Einführung und Anforderungen sagt:

    [...] Nützliche Komponenten Zend_Log und Zend_Mail [...]

  6. Thomas Peterson sagt:

    Hey

    was hältst du denn von Prado und Symfony?

  7. Ralfs PHP Blog » Zend Framework Tutorial Teil 10: Sinnvoll cachen mit Zend_Cache sagt:

    [...] Tutorial, Zend Framework, Zend Framework Tutorial, Zend Cache Bookmark: del.icio.us yigg.de mister-wong.de  [...]

  8. Ralf Eggert sagt:

    Hallo Thomas,

    habe ich mir beides angeschaut. Bei Symfony wäre ich wohl gelandet, wenn nicht das Zend Framework aufgetaucht wäre. Mit Prado konnte ich mich aber nicht so recht anfreunden.

    Gruß,

    Ralf

  9. Bleu sagt:

    Hi Ralf

    wann wird denn dieses Tutorial fertiggestellt, sprich wann kommt Teil 12...? Es hat mir bisher sehr geholfen und brenne darauf mehr zu lernen.

    MfG

  10. Ralf Eggert sagt:

    Moin Bleu,

    derzeit liegt das Tutorial von meiner Seite auf Eis. Die Arbeit geht zur Zeit vor. Es ist aber geplant, das Tutorial umzuziehen, so dass mehrere Leute daran mitarbeiten können. Leider habe ich in den letzten Wochen aber zu wenig Zeit gehabt, mich aktiv um den Umzug zu kümmern. Ich hoffe aber, dass es bald neues dazu gibt.

    Gruß,

    Ralf

  11. Michael sagt:

    Hallo Ralf.

    Du bist Schuld! Ja! - Denn jetzt hast du mich endgültig von diesem genialen Framework überzeugt und jetzt fühle ich mich auch noch dazu genötigt, mich damit zu beschäftigen und damit Ärger mit Madame zu riskieren, die ohnehin schon langsam ungeduldig wird :D

    Ich freue mich schon wahnsinnig auf den Abschluss deines Tutorials, das fast schon als Buch durchgehen könnte. Sollte es mal davon ein Buch geben, bin ich der erste, der das kauft.

    Hoffen wir, dass du bald wieder mehr Zeit hast und das Tutorial wieder aus der Kühltruhe holst. Denn es warten sicher nicht wenige Leser gespannt auf einen krönenden Abschluss.

    Viele Grüße auch Sachsen und herzlichen Dank für die Mühen des Tutorialschreibens,

    Michael

  12. Hannes sagt:

    Hallo Ralf,

    vielen Dank für dieses wunderbare Tutorial. Ich bin schon sehr gespannt wie es weitergeht. Vor allem die Benutzung von Smarty interessiert mich sehr, da ich keine Projekte mehr ohne Smarty baue.

    Gruss
    Hannes

  13. Andreas Pankratz sagt:

    Hallo Ralf,

    Vielen Dank für die Mühe die du dir bis jetzt gemacht hast.

    Bin ebenfalls gespannt wie Smarty eingebunden wird.

    Gruß
    Andreas

  14. www.simonfella.de » Blog Archiv » Tutorial Zend Framework ver 0.2 sagt:

    [...] Nützliche Komponenten Zend_Log und Zend_Mail [...]

  15. Marcel sagt:

    Absolut tolles Tutorial. Ich habe jetzt Wochen damit zugebracht mich ins Zend Framework einzuarbeiten weil einfach kein schlaues Tutorial zu finden war. Jetzt, nachdem das Gerüst meiner Applikation steht finde ich deins - Murphys Law in Reinkultur :-)

    Ich werde es aber in meiner Bookmarkliste behalten um mir die eine odere andere Anregung zu holen.

Hinterlasse eine Antwort