[MVC/CakePHP] Waar verzend je een e-mail

Pagina: 1
Acties:

Onderwerpen


Acties:
  • 0 Henk 'm!

  • djluc
  • Registratie: Oktober 2002
  • Laatst online: 08-09 11:16
Ik ben bezig met het verzenden van e-mails in een MVC structuur. Hierover bestaat veel discussie, met name over het punt waar je besluit een mail te verzenden. De case is: Een nieuw bericht wordt toegevoegd en daardoor moet er een e-mail de deur uit.

Opties:

Controller
Het sturende element binnen de software. Nadeel: Het garandeert niet dat de e-mail altijd verzonden wordt. Bijvoorbeeld als je de via een ander proces zoals een cron of api berichten toevoegt. Voordeel: Je kiest bewust voor verzending. Denk bijvoorbeeld aan wat er kan gebeuren als je ineens een reeks records gaat importeren.

Model
Lijkt logisch want het zekert dat deze actie uitgevoerd wordt. Aan de andere kant is het geen bewuste keuze meer, nieuw records -> mail wordt verzonden. Daarnaast wordt het model wat grotere (niets mis mee) en bevat het extra functies die eigenlijk niet meer concreet met het model te maken hebben.
http://www.robbyonrails.c...controllers-versus-models

Observer
Het probleem van gemixte code in het model wordt opgelost door deze in een observer te stoppen. Deze triggert onder bepaalde voorwaarden en regelt de verzending van de mail. Zo heb je weer scheiding tussen functies en wordt je save() methode in het model niet vervuilt met details over mails.

Een e-mail is een object
Een e-mail kan je zien als een ding, net zoals een bericht. Alternatieve optie: Maak een nieuw model aan: E-mail. Daar heb je dan tevens een optie om deze op te slaan bijvoorbeeld. Het is een totaal aparte actie en zo trek je dat geheel uit de flow.

Je request is dan dus:
Nieuw bericht wordt verzonden (formulier): controller -> model -> controller -> view (OK)

Ergens in die stappen start er een nieuwe request:
Nieuwe mail (inhoud): controller -> model -> controller -> view (e-mail template)

De view wordt dan verzonden per e-mail dus. De situatie is dan dus dat een request een nieuwe request opstart. Voordeel is tevens dat bijvoorbeeld een mailque gemaakt kan worden. Je hoeft alleen in het model de mails in plaats van opslaan deze naar bijvoorbeeld een que server te sturen.

Wat is jullie ervaring, wat is handig en wijsheid?

Acties:
  • 0 Henk 'm!

  • Exception
  • Registratie: Augustus 2006
  • Laatst online: 09:52
Ik zou hem zelf in de controller verzenden, en de opmaak en inhoud in een view zetten. Dit lijkt mij het meest logische. Het email-model zorgt voor de het interne proces. Dus aanroepen van de e-mail functies etc.

Correct me if i'm wrong, begin ook net met MVC :)

Acties:
  • 0 Henk 'm!

  • djluc
  • Registratie: Oktober 2002
  • Laatst online: 08-09 11:16
Tnx voor je reactie. "Het email-model zorgt voor de het interne proces." Je zegt in zin 1 vanuit de controller verzenden maar je hebt het ook over een email-model. Wat bedoel je precies?

Acties:
  • 0 Henk 'm!

  • PatrickH89
  • Registratie: November 2009
  • Laatst online: 10-09 20:58
Als je je echt aan de MVC structuur wilt houden dan moet je de email verzenden vanuit de controller, want de model is er puur om om te gaan met data op te halen en erin te stoppen. Mijns inziens moet er in de controller een aanroep naar een email library (=email object) staan en moet de email verzonden worden.

Als je niet veel waarde hecht aan volledige integere MVC structuur dan kun je eraan denken om hem uit de model te versturen.

Acties:
  • 0 Henk 'm!

  • Janoz
  • Registratie: Oktober 2000
  • Laatst online: 09-09 16:17

Janoz

Moderator Devschuur®

!litemod

MVC is een UI pattern. Model is puur de representatie van je domein. Daar hoort niet je businesslogic in. Mail versturen is een service die je vanuit je controler aan zou moeten roepen lijkt mij.

Ken Thompson's famous line from V6 UNIX is equaly applicable to this post:
'You are not expected to understand this'


Acties:
  • 0 Henk 'm!

  • djluc
  • Registratie: Oktober 2002
  • Laatst online: 08-09 11:16
Janoz schreef op donderdag 01 december 2011 @ 20:05:
MVC is een UI pattern. Model is puur de representatie van je domein. Daar hoort niet je businesslogic in. Mail versturen is een service die je vanuit je controler aan zou moeten roepen lijkt mij.
Interessant!

Ik begrijp dat je dus stelt dat de business logic dus in controllers thuis hoort want in de view neem ik niet aan?

Wat ik vooral lees is dat je de businesslogic juist wel in de models plaatst om op die manier een centrale en testbare plek hebt waar alles verwerkt wordt. De controller roept de juiste zaken aan. Fat models skinny controllers e.d.

Of redeneer je wellicht vanuit een anders framework dan een CakePHP waarin je nog andere opties hebt?

Acties:
  • 0 Henk 'm!

  • Avalaxy
  • Registratie: Juni 2006
  • Laatst online: 13:13
Nee nee, domain logic stop je in je models (eigenlijk 'domain', waarin je dan weer entities hebt die je om kunt zetten naar viewmodels of DTO's), business logic in je controllers (eigenlijk in aparte classes, maar die roep je aan vanuit je controllers) en in je views hoort absoluut alleen maar presentationlogic; logica die echt specifiek voor die view is.

[ Voor 16% gewijzigd door Avalaxy op 01-12-2011 20:36 ]


Acties:
  • 0 Henk 'm!

  • Patriot
  • Registratie: December 2004
  • Nu online

Patriot

Fulltime #whatpulsert

djluc schreef op donderdag 01 december 2011 @ 20:20:
[...]
Interessant!

Ik begrijp dat je dus stelt dat de business logic dus in controllers thuis hoort want in de view neem ik niet aan?

Wat ik vooral lees is dat je de businesslogic juist wel in de models plaatst om op die manier een centrale en testbare plek hebt waar alles verwerkt wordt. De controller roept de juiste zaken aan. Fat models skinny controllers e.d.

Of redeneer je wellicht vanuit een anders framework dan een CakePHP waarin je nog andere opties hebt?
Businesslogic is in principe datgene wat je in de controller zet. Businesslogic is de logica die database (model) en interface (view) aan elkaar hangt. Fat models, skinny controllers, gaat meer over het goed na moeten denken over wat je in je controller zet en wat je in je model zou moeten zetten.

In je model tref je meestal dingen aan die echt betrekking hebben tot opvragen of mutatie van de gegevens. In jouw geval heb je in je model een methode waarmee je in de controller de gegevens opvraagt (in jouw geval waarschijnlijk find()) en daar stuur je de mail. Het versturen van de mail heeft niks meer met de gegevens te maken.

Acties:
  • 0 Henk 'm!

  • djluc
  • Registratie: Oktober 2002
  • Laatst online: 08-09 11:16
Ah nu snappen we elkaar. Ik geloof er inderdaad in dat een hoop gewoon in het model thuis hoort. Bijvoorbeeld bepaalde gegevens opzoeken maar ook bepaalde gegevens verzamelen en vervolgens doorsturen naar de controller. Ook een berekening (businesslogic) hoort daar wat mij betreft thuis.

Ik wil eigenlijk niks inhoudelijks in die controllers hebben. Dat geeft met goed overzicht vandaar dat ik die e-mail ook weg wil hebben:

PHP:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
App::uses('CakeEmail', 'Network/Email');
class MessagesController extends AppController {
    
    
    public function index() {
        $this->set('messages', $this->Message->find('all'));
        
        //handle saving in index because this is the place where messages are made and editted
        if($this->request->is('post')) {
            if($this->Message->save($this->request->data)) {
                $this->Session->setFlash('Your message has been saved.');
                
                
                //currently sending out e-mail here, not sure whether it should stay here.
                //most likely we pack it into components so we can just call them
                $email = new CakeEmail();
                $email->from(array('test@example.com' => ''))
                    ->to('test@example.com')
                    ->subject('About')
                    ->send('My message');
                
                $this->redirect(array('action' => 'index'));
            }else{
                $this->Session->setFlash('Saving the message failed');
                $this->render('index');
            }
        }
    }
}

Acties:
  • 0 Henk 'm!

  • YopY
  • Registratie: September 2003
  • Laatst online: 13-07 01:14
Voor het bouwen van een e-mail zou ik eerder een email service gaan bouwen waar je bijvoorbeeld een adres en een instantie van een van je model-objecten - zoals een bestelling oid - in gooit. Eigenlijk is het een service met een view - de service roep je aan met de data die relevant is voor het versturen van een e-mail, en de mailer service stuurt dat weer door naar een view om er een HTML e-mail van te maken. Vervolgens verstuurt de mailer service het op wat voor manier dan ook, bijvoorbeeld door het weer door te sturen naar een extern mailsysteem.

Dus in je bovenstaande voorbeeld zou het zoiets worden:

PHP:
1
2
3
4
5
6
7
8
9
10
11
12
13
class MessagesController extends AppController {
    private $mailer;
    function __construct($mailer) {
        $this->mailer = $mailer;
    }

   public function index() {
       // bla
       $contents = $backend->getContents(1337); // of whatever.
       $mailer->sendMail($user->email, $contents);
       // de rest
    }
}


oid. Zaken als standaard 'from' en reply-to headers kun je in settings kwijt, subject en inhoud komen uit het model object ($contents). Eigenlijk is de mailer ook een soort controller, daar je waarschijnlijk meerdere types mail hebt - $mailer->sendOrderConfirmationEmail($user, $order) bijvoorbeeld.

Acties:
  • 0 Henk 'm!

  • Herko_ter_Horst
  • Registratie: November 2002
  • Niet online
@Janoz: ik ben het niet met je eens dat MVC een UI pattern is. Het is een algemeen bruikbare architectuur die gaat over separation of concerns: het datamodel/datahuishouding(M), datapresentatie en -interactie(V) en businesslogica(C).

@TS, zoals Patriot al aangeeft: je model is in elk geval de "verkeerde" plek. De Controller zoals je hem nu omschrijft zou kunnen, maar ik zou eerder denken aan een tweede View, namelijk de (read-only) BerichtNaarEmailView. Deze zou inderdaad als observer bij het model geregistreerd kunnen staan en wijzigingen in het model (d.w.z. het toevoegen van een bericht) kunnen "renderen" als het sturen van een e-mail.

"Any sufficiently advanced technology is indistinguishable from magic."


Acties:
  • 0 Henk 'm!

  • mithras
  • Registratie: Maart 2003
  • Niet online
(Disclaimer: ik ben Zend Framework gebruiker en gebruik ook die terminologie)

De algemene tendens is fat model skinny controller. De controller zie je daarbij als politieagent die gegevens ontvangt van een Request en via zorgt voor een Response. Je model zorgt voor de domain logic.

Ik zou hier een service laag in implementeren (je model layer is meer dan puur entiteiten) die verder de berichten afhandelt. Je controller regelt puur het verkeer (de post data) en verder niets. Het sturen van een mail zou ik ook niet als entiteit neerzetten: een mailbericht kan je wel als zodanig implementeren. Een voorbeeldje:

PHP:
1
2
3
4
5
6
7
8
9
10
11
12
13
class IndexController extends ActionController
{
    public function indexAction ()
    {
        if ($this->getRequest()->isPost()) {
            $service = new MessageService();
            $message = $service->persistMessage($this->getRequest()->getPost());
            
            $mail = new MailService();
            $mail->sendMessage($message);
        }
    }
}
offtopic:
In ZF zou je er nog een Form tussen zetten, ter validatie en eenvoud


Wellicht dat je hier en daar nog een check wilt maken of het is gelukt e.d., maar dit is de basis :)

[ Voor 16% gewijzigd door mithras op 01-12-2011 20:57 ]


Acties:
  • 0 Henk 'm!

  • Patriot
  • Registratie: December 2004
  • Nu online

Patriot

Fulltime #whatpulsert

Wat de TS in zijn laatste post al bijna heeft lijkt mij de ideal optie. Hij mist alleen nog het gebruik van de template() functie, waarmee hij een view kan specificeren als bron van de inhoud van het mailtje. Op die manier is het bovendien mogelijk om zowel te werken met een plaintext versie als een HTML-versie.

Dat is in feite ook gewoon wat YopY en mithras zeggen, btw.
Herko_ter_Horst schreef op donderdag 01 december 2011 @ 20:54:

@TS, zoals Patriot al aangeeft: je model is in elk geval de "verkeerde" plek. De Controller zoals je hem nu omschrijft zou kunnen, maar ik zou eerder denken aan een tweede View, namelijk de (read-only) BerichtNaarEmailView. Deze zou inderdaad als observer bij het model geregistreerd kunnen staan en wijzigingen in het model (d.w.z. het toevoegen van een bericht) kunnen "renderen" als het sturen van een e-mail.
Dat impliceert dat iedere wijziging van het model een mail tot gevolg moet hebben, dat is niet het geval lijkt mij.

Acties:
  • 0 Henk 'm!

  • Herko_ter_Horst
  • Registratie: November 2002
  • Niet online
Patriot schreef op donderdag 01 december 2011 @ 20:59:
Dat impliceert dat iedere wijziging van het model een mail tot gevolg moet hebben, dat is niet het geval lijkt mij.
Dat hoeft niet, de View hoeft niet te reageren op een notificatie.

"Any sufficiently advanced technology is indistinguishable from magic."


Acties:
  • 0 Henk 'm!

  • Patriot
  • Registratie: December 2004
  • Nu online

Patriot

Fulltime #whatpulsert

Herko_ter_Horst schreef op donderdag 01 december 2011 @ 21:00:
[...]

Dat hoeft niet, de View hoeft niet te reageren op een notificatie.
Dan bepaal je in de view of er een mail gestuurd gaat worden? Dat lijkt me niet iets wat je daar moet willen. Volgens mij is de controller de enige plek waarin je weet of het wel of niet gepast is om een mail te sturen.

Acties:
  • 0 Henk 'm!

  • Spockz
  • Registratie: Augustus 2003
  • Laatst online: 10-09 09:08

Spockz

Live and Let Live

Het lijkt mij dat je in de controller alleen maar zegt dat je een bepaald mailtje wilt versturen naar een bepaalde plek. Je laat de inhoud genereren door middel van een view. Je bouwt het mailtje verder op (To, From etc.) en duwt het door naar de service die de mail gaat versturen.

Afhankelijk van of je dat nodig hebt zou je ook een model kunnen maken voor je Mail deze kan je dan in de DB opslaan. Bijvoorbeeld om altijd een history te hebben van de mails die je hebt verstuurd. (Wel handig voor facturen e.d.)

C'est le ton qui fait la musique. | Blog | @linkedin
R8 | 18-55 IS | 50mm 1.8 2 | 70-200 2.8 APO EX HSM | 85 1.8


Acties:
  • 0 Henk 'm!

  • Janoz
  • Registratie: Oktober 2000
  • Laatst online: 09-09 16:17

Janoz

Moderator Devschuur®

!litemod

Herko_ter_Horst schreef op donderdag 01 december 2011 @ 20:54:
@Janoz: ik ben het niet met je eens dat MVC een UI pattern is. Het is een algemeen bruikbare architectuur die gaat over separation of concerns: het datamodel/datahuishouding(M), datapresentatie en -interactie(V) en businesslogica(C).
Separation of concerns kan op vele lagen. Bij kleine applicaties is MVC misschien voldoende, maar bij grotere zou je controler wel heel groot worden. MVC is dan verantwoordelijk voor het UI deel en in de controler wordt vervolgens gewoon de servicelaag van de businesslogic aangeroepen.

Ken Thompson's famous line from V6 UNIX is equaly applicable to this post:
'You are not expected to understand this'


Acties:
  • 0 Henk 'm!

  • Herko_ter_Horst
  • Registratie: November 2002
  • Niet online
Janoz schreef op donderdag 01 december 2011 @ 21:22:
[...]

Separation of concerns kan op vele lagen. Bij kleine applicaties is MVC misschien voldoende, maar bij grotere zou je controler wel heel groot worden. MVC is dan verantwoordelijk voor het UI deel en in de controler wordt vervolgens gewoon de servicelaag van de businesslogic aangeroepen.
Dit gaat behoorlijk off-topic, maar in een grotere applicatie is er natuurlijk niet maar één MVC. Het kan best zijn dat een combinatie van MVC op één niveau de rol van Model speelt op een ander niveau (random voorbeeld via Google: http://techportal.ibuildi...oads/2010/02/MVC-HMVC.png).

[ Voor 6% gewijzigd door Herko_ter_Horst op 01-12-2011 21:27 ]

"Any sufficiently advanced technology is indistinguishable from magic."


Acties:
  • 0 Henk 'm!

  • Janoz
  • Registratie: Oktober 2000
  • Laatst online: 09-09 16:17

Janoz

Moderator Devschuur®

!litemod

Dat is het PAC pattern ;)

Ken Thompson's famous line from V6 UNIX is equaly applicable to this post:
'You are not expected to understand this'


Acties:
  • 0 Henk 'm!

  • Herko_ter_Horst
  • Registratie: November 2002
  • Niet online
Foutje, ik had hierarchical MVC in m'n hoofd, om de een of andere reden kwam het PAC plaatje als eerste naar voren (lijkt er ook erg veel op natuurlijk).

"Any sufficiently advanced technology is indistinguishable from magic."


Acties:
  • 0 Henk 'm!

  • djluc
  • Registratie: Oktober 2002
  • Laatst online: 08-09 11:16
Leuk dat het zo'n interessant topic wordt!

Dat hierarchical MVC is ook erg interessant, had het nog niet eerder gezien!

Volgens mij is het redelijk duidelijk: Je initieert het verzenden van een e-mail vanuit de controller. Daarover lijkt maar weinig discussie te bestaan. Een observer hoor ik ook niemand over dus dat is sowieso niets? Of is dat omdat het redelijk weinig gebruikt wordt?

Het codevoorbeeld wat ik gepost heb betreft de nieuwe mailfuncties van CakePHP, die zijn inderdaad al aardig ingericht en ondersteunen templates. Dat zou dus prima kunnen dienen als de service.

Het nadeel wat ik zie van het in de controller stoppen is dat je het dus steeds apart inbouwt. Dus in een API moet je opnieuw die mail samenstellen en verzenden. Dat is het unieke maar dat komt uiteraard geen 100x voor dus het is goed te overzien. Het gaat me met name over best practices.

Acties:
  • 0 Henk 'm!

  • Spockz
  • Registratie: Augustus 2003
  • Laatst online: 10-09 09:08

Spockz

Live and Let Live

Dat hangt er natuurlijk vanaf hoeveel verschillende soorten mails je hebt. Je kunt natuurlijk als je merkt dat je bepaalde mails in verschillende controllers of actions verstuurt twee dingen doen:
  1. Zorg ervoor dat je de code die de mail aanmaakt en verstuurt naar een aparte plek refactort zodat je alleen nog maar een functie aan hoeft te roepen om de mail verstuurt te krijgen. Dit is een voorbeeld, het doel is code-duplicatie te voorkomen.
  2. Een andere manier om er tegenaan te kijken is dat je misschien niet helemaal lekker bezig bent voor de gebruiker. Waarom zijn er twee verschillende controlers / actions die eenzelfde mail versturen? Is dat wel zo duidelijk / simpel voor de gebruiker? Krijg je hierdoor niet dezelfde functionaliteit op meerdere plekken? Misschien moet je de indeling van je site veranderen. (Of je programma.)

C'est le ton qui fait la musique. | Blog | @linkedin
R8 | 18-55 IS | 50mm 1.8 2 | 70-200 2.8 APO EX HSM | 85 1.8


Acties:
  • 0 Henk 'm!

  • Herko_ter_Horst
  • Registratie: November 2002
  • Niet online
Als je meerdere manieren hebt om je model te manipuleren zul je moeten bedenken hoe je daar mee om wilt gaan en hoe die diverse manieren gaan communiceren.

Observers/listeners/notifications zijn dan wel degelijk een optie: iedereen die geinteresseerd is in de staat van het model registreert zich als observer en krijgt een notificatie als er iets verandert.

Uiteraard kun je ook alles via één controller laten lopen, maar dan ligt wel het God-object anti-pattern op de loer.

"Any sufficiently advanced technology is indistinguishable from magic."


Acties:
  • 0 Henk 'm!

  • Patriot
  • Registratie: December 2004
  • Nu online

Patriot

Fulltime #whatpulsert

Volgens mij wordt er nu een probleem gemaakt dat er niet is :? Voor iedere mail zal er iets in je code moeten zitten. Je kunt eventueel een extra methode in je (App)Controller zetten waar je een CakeEmail object maakt en de mail laat verzenden, maar dat zou ik alleen doen als je op meerdere plekken steeds dezelfde mail moet versturen. Anders ben je een (imo) nutteloze wrapper aan het schrijven.
Pagina: 1