• Najnowsze pytania
  • Bez odpowiedzi
  • Zadaj pytanie
  • Kategorie
  • Tagi
  • Zdobyte punkty
  • Ekipa ninja
  • IRC
  • FAQ
  • Regulamin
  • Książki warte uwagi

Obsługa formularza kontaktowego w Laravelu. Zachowanie SOLID i dobre wzorce

Object Storage Arubacloud
0 głosów
462 wizyt
pytanie zadane 12 lutego 2020 w PHP przez Artek Stary wyjadacz (11,800 p.)
edycja 12 lutego 2020 przez Artek

Aplikację tworzę w Laravel'u. Mam formularz kontaktowy. Formularz trzeba wyświetlić. Po submitowaniu formularza trzeba dokonać walidacji danych i wysłać wiadomość. Wiem jak zrobić aby wszystko działało. Zależy mi jednak na tym aby napisać 100% czysty kod i aby zachować SOLID - tak aby nie można było się do niczego przyczepić.

Pierwsza kwestia : kontrollery - zrobić jeden kontroller  i stworzyć dwie metody 1 - showContactForm, 2 - sendMessage. Czy może zrobić dwa kontrollery jeden do wyświetlania strony z formularzem a drugi do wysyłania wiadomości, każdy zawierający jedną metodę?

Druga kwestia, jak należałoby zapisać kod wysyłający wiadomość? Naklepanie wszystkiego po kolei w kontrolerze nie jest dobrym pomysłem.  Przemyślałem wszystko i postanowiłem zorganizować kod w ten sposób. Npiszcie mi co o tym myślicie.

Kod kontrolera

namespace App\Http\Controllers;

use Illuminate\Http\Request;
use App\Constans\NotificationType;
use App\Factories\NotificationsFactory;

class SendMessageFromUserController extends Controller
{
    private $notification;

    public function __construct(NotificationsFactory $notificationFactory)
    {
       $this->notification = $notificationFactory->getInstance(NotificationType::SEND_MAIL_TO_OWNER);
    }

    public function sendMessageFromUser()
    {
       return $this->notification->notify();
    }
}

Kod fabryki powiadomień

namespace App\Factories;

use App\Constans\NotificationType;
use App\Interfaces\Notifiable;
use App\Notifications\Validators\MailMessageFromUserValidator;
use App\Notifications\Validators\MailMessageFromUser;


class NotificationsFactory
{
	public function getInstance(NotificationType $notificationType) : Notifiable
	{
         switch($notificationType)
         {
         	case NotificationType::SEND_MAIL_TO_OWNER:
              return $this->buildOwnerMailNotification();
         	break;
         }
	}

	private function buildOwnerMailNotification()
	{
        $validator =  new MailMessageFromUserValidator();
        return new MailMessageFromUser($validator);
	}
}

Kod klasy wysyłającej maila

namespace App\Notifications;

use App\Interfaces\NotificationValidator;
use App\Interfaces\Notifiable;

class MailMessageFromUser implements Notifiable
{
   private $validator;

   public function __construct(NotificationValidator $validator)
   {
     $this->validator = $validator;
   }

   public function validate()
   {

   }

   public function notify()
   {
   	
   }
}

Kod walidatora


namespace App\Notifications\Validators;

use App\Interfaces\NotificationValidator;

class MailMessageFromUserValidator implements NotificationValidator
{
	
	public function validateNotification($message)
	{

	}
}

Może tak być?

2 odpowiedzi

+3 głosów
odpowiedź 13 lutego 2020 przez Comandeer Guru (600,330 p.)
Przekombinowane to.

Kontroler nie powinien dostawać fabryki powiadomień. Fakt, że dostaje fabrykę, sprawia, że sam decyduje, jaki typ powiadomienia stworzyć (w tym wypadku mailowe). Kontroler nie powinien tego wiedzieć, on po prostu powinien dostać z zewnątrz dowolny typ powiadomienia (zasady L i D).

Klasa wysyłająca maile IMO nie powinna zajmować się równocześnie walidacją danych. Ten krok powinien być wykonany przed przekazaniem danych do klasy wysyłającej. A to oznacza, że fabryka nie jest w tym momencie potrzebna, bo walidator i klasa wysyłająca są całkowicie rozdzielne.

No i klasa wysyłająca maile raczej nie powinna być związana z konkretnym use-case'em, ale po prostu być w stanie wysłać dowolny mail pasujący do wzoru.
komentarz 13 lutego 2020 przez Artek Stary wyjadacz (11,800 p.)
Dzięki za informacje. Generalnie rozumiem co masz na myśli. A byłbyś w stanie pokazać jak ten kod powinien wyglądać?
komentarz 14 lutego 2020 przez Artek Stary wyjadacz (11,800 p.)

@Comandeer, W sumie najbardziej zastanawia mnie 

Kontroler nie powinien tego wiedzieć, on po prostu powinien dostać z zewnątrz dowolny typ powiadomienia

I właśnie nie wiem jak dokładnie to zapisać. Z zewnątrz czyli dokładnie skąd? Gdzie to wstrzyknąć? W którym momencie?

komentarz 14 lutego 2020 przez Comandeer Guru (600,330 p.)

I właśnie nie wiem jak dokładnie to zapisać. Z zewnątrz czyli dokładnie skąd? Gdzie to wstrzyknąć? W którym momencie?

Tam, gdzie obecnie wstrzykujesz fabrykę.

 

komentarz 14 lutego 2020 przez Artek Stary wyjadacz (11,800 p.)

No czyli w konstruktorze. Tylko, że o ile mi wiadomo w laravelu nie ma możliwości coś wstrzykiwać przez konstruktor w kontrolerze. Nigdzie nie pisze się

$controller = new SendMessageFromUserController()

Podaje się tylko adres url, odpowiadający mu kontroler i metodę uruchamianą

Route::post('/kontakt', 'SendMessageFromUserController@sendMessageFromUser');

I reszta dzieje się automatycznie.

Jedyne co to można pobrać parametry z adresu url i wykorzystać je w metodzie

komentarz 15 lutego 2020 przez Comandeer Guru (600,330 p.)
No ok, ale laravel ma jakąś formę DIC-a: https://laravel.com/docs/5.8/container
komentarz 15 lutego 2020 przez Artek Stary wyjadacz (11,800 p.)

Tak, tylko problem jest taki. Aby service container zadziałał musiałbyć jako type hint parametru konstruktora podać nazwę konkretnej klasy. Jak rozumiem stoi to w sprzeczności z tym co napisałeś wcześniej, czyli :

Kontroler nie powinien tego wiedzieć, on po prostu powinien dostać z zewnątrz dowolny typ powiadomienia (zasady L i D)

Podanie jako type hint interface'u nie pomoże bo service container nie wie co dokładnie ma wstrzyknąć.

komentarz 15 lutego 2020 przez Comandeer Guru (600,330 p.)

Bardziej mi chodziło o https://laravel.com/docs/5.8/container#the-make-method ale słuszna uwaga. W tym momencie lepiej zdać się na automatyczny mechanizm i podać dokładną klasę.

0 głosów
odpowiedź 14 lutego 2020 przez Artek Stary wyjadacz (11,800 p.)

Po poprawkach

kontroler

namespace App\Http\Controllers;

use Illuminate\Http\Request;
use App\Interfaces\NotificationValidator;
use App\Interfaces\Notifier;
use App\Notifications\SendEmail;
use App\Mail\SimpleEmail;


class SendMessageFromUserController extends Controller
{
    
    public function sendMessageFromUser(Request $request)
    {
       $data = $request->validate([
          'email' => 'max:30',
          'subject' => 'max:30',
          'message' => 'required|min:3|max:1000'
       ]);

       $notification = new SendEmail(new SimpleEmail($data['message'], $data['subject'], $data['email']), 
       	config('mail.management_email'));
      
       return $notification->notify();
    }
}

Klasa wysyłająca maila

namespace App\Notifications;


use App\Interfaces\Notifier;
use App\Mail\MessageFromUser;
use Mail;
use Illuminate\Mail\Mailable;

class SendEmail implements Notifier
{
   private $mail;
   private $receipient;

   public function __construct(Mailable $mail,$receipient)
   {
     $this->mail = $mail;
     $this->receipient = $receipient;
   }

   public function notify()
   {
      Mail::to($this->receipient)->send($this->mail);

      return Mail::failures() ? back()->withErrors(['Nieoczekiwany błąd podczas wysyłania wiadomości']) : back()->with('success','Pomyślnie wysłano wiadomość');
 
   }
}

Klasa budująca maila

namespace App\Mail;

use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Mail\Mailable;
use Illuminate\Queue\SerializesModels;

class SimpleEmail extends Mailable
{
    use Queueable, SerializesModels;

    private $sender;
    private $msg;

    /**
     * Create a new message instance.
     *
     * @return void
     */
    public function __construct($msg, $subject = "Brak tematu",$sender = "Brak adresu")
    {
        $this->subject = empty($subject) ? "Brak tematu" : $subject;
        $this->sender = empty($sender) ? "Brak adresu" : $sender;
        $this->msg = $msg;
    }

    /**
     * Build the message.
     *
     * @return $this
     */
    public function build()
    {

        return $this->from($this->sender)
                    ->view('mails.simple_email')
                    ->subject($this->subject)
                    ->with(['messageContent' => $this->msg]);
    }
}

Proszę krytkować

Podobne pytania

0 głosów
1 odpowiedź 149 wizyt
pytanie zadane 10 czerwca 2020 w PHP przez XiverKi Bywalec (2,050 p.)
0 głosów
3 odpowiedzi 549 wizyt
pytanie zadane 17 lutego 2018 w PHP przez sapero Gaduła (4,100 p.)
0 głosów
3 odpowiedzi 366 wizyt
pytanie zadane 22 października 2019 w PHP przez Artek Stary wyjadacz (11,800 p.)

92,536 zapytań

141,376 odpowiedzi

319,452 komentarzy

61,920 pasjonatów

Motyw:

Akcja Pajacyk

Pajacyk od wielu lat dożywia dzieci. Pomóż klikając w zielony brzuszek na stronie. Dziękujemy! ♡

Oto polecana książka warta uwagi.
Pełną listę książek znajdziesz tutaj.

Akademia Sekuraka

Kolejna edycja największej imprezy hakerskiej w Polsce, czyli Mega Sekurak Hacking Party odbędzie się już 20 maja 2024r. Z tej okazji mamy dla Was kod: pasjamshp - jeżeli wpiszecie go w koszyku, to wówczas otrzymacie 40% zniżki na bilet w wersji standard!

Więcej informacji na temat imprezy znajdziecie tutaj. Dziękujemy ekipie Sekuraka za taką fajną zniżkę dla wszystkich Pasjonatów!

Akademia Sekuraka

Niedawno wystartował dodruk tej świetnej, rozchwytywanej książki (około 940 stron). Mamy dla Was kod: pasja (wpiszcie go w koszyku), dzięki któremu otrzymujemy 10% zniżki - dziękujemy zaprzyjaźnionej ekipie Sekuraka za taki bonus dla Pasjonatów! Książka to pierwszy tom z serii o ITsec, który łagodnie wprowadzi w świat bezpieczeństwa IT każdą osobę - warto, polecamy!

...