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

Symfony czy w serwisach można rzucać wyjątkami

Object Storage Arubacloud
0 głosów
561 wizyt
pytanie zadane 1 lutego 2019 w PHP przez `Krzychuu Stary wyjadacz (13,940 p.)
edycja 1 lutego 2019 przez `Krzychuu

Witam

Czy mogę tworzyć wyjątki w klasie serwisu? np. 

throw new HttpException(400, "Nazwa zajęta!");

Załóżmy że dodaje rekord do bazy danych w serwisie sprawdzam czy istnieje rekord o takiej samej nazwie jeżeli istnieje to lepiej będzie wyrzucić wyjątek taki jak wyżej czy zwrócić do kontrolera błąd i tam zwrócić nazwę i kod błędu?

3 odpowiedzi

+2 głosów
odpowiedź 1 lutego 2019 przez Comandeer Guru (601,110 p.)
wybrane 2 lutego 2019 przez `Krzychuu
 
Najlepsza

Usługa raczej powinna rzucać wyjątki dotyczące tego co robi, np. brak połączenia z bazą – wyjątek NoDBConnectionException lub podobny. Warstwa HTTP to nie jest coś, czym powinna się zajmować usługa.

Dodatkowo wyjątki powinny dotyczyć – jak sama nazwa sugeruje – sytuacji wyjątkowych. Owszem, można wszelkie błędy obsługiwać przy pomocy wyjątków, ale wówczas w kontrolerze narośnie nam wiele bloków try/catch obsługujących poszczególne rzeczy. W tym wypadku zwróciłbym po prostu informację, że rekord nie został dodany, z opcjonalną informacją czemu. Innymi słowy: wyjątki zostawiłbym dla błędów niezależnych od naszego kodu (brak połączenia z bazą, niemożność zapisu do pliku itd.), a błędy związane bezpośrednio z działaniem aplikacji czy błędnie wprowadzonymi przez użytkownika danymi (a zatem błędami, o których użytkownik powinien się dowiedzieć) obsługiwałbym "normalnie".

Ogólnie to widziałbym to jakoś tak:

<?php
public function handleRequest( $req ) {
	try {
		if ( !$this->myService->saveToDB( $req ) ) {
			// Nie zapisano, trzeba wyświetlić błąd użytkownikowi.
		}
	} catch( Exception $e ) {
		// Baza się krzakła.
		throw new HTTPException( 500 );
	}
}

W sumie tutaj jest fajny artykuł opisujący dokładniej to, o czym napisałem: http://adam.wroclaw.pl/2015/05/wyjatki-kiedy-jak-i-po-co/

Oczywiście można też stosować podejście zupełnie odwrotne: https://zawarstwaabstrakcji.pl/20170309-walidacja-w-architekturze-wielowarstwowej/ – pytanie, na ile chcemy komplikować całość.

komentarz 2 lutego 2019 przez HaKIM Szeryf (87,590 p.)

Nie ma najlepszej. Wszystko zależy od projektu, języka, frameworka lub jego braku, architektury, czasu (deadline) i masy innych czynników.

Powiedziawszy to możesz zajrzeć do:

https://symfony.com/doc/current/validation.html

I odpowiedzieć sobie na pytanie czy jest to dobre rozwiązanie dla Twojego projektu.

komentarz 2 lutego 2019 przez `Krzychuu Stary wyjadacz (13,940 p.)
Tzn chodzi mi bardziej jaki response zwrócić, żeby odczytać że konkretnie o ten błąd chodzi.
komentarz 2 lutego 2019 przez HaKIM Szeryf (87,590 p.)

Jeśli chodzi o konflikt dwóch takich samych rekordów to (w Symfony):

$message = $exception->getMessage() ?? 'Something went wrong';

return new Response($message, Response::HTTP_CONFLICT);

I sprawdzasz np. Ajax zwracany status code.

Ale z tego co widziałem to Ty korzystasz z walidatora Symfony, a tam to trochę inaczej wygląda.

Odsyłam do dokumentacji: https://symfony.com/doc/current/validation.html

komentarz 2 lutego 2019 przez `Krzychuu Stary wyjadacz (13,940 p.)
Dziękuje za pomoc :)
komentarz 2 lutego 2019 przez Comandeer Guru (601,110 p.)

Nie potrafię sobie wyobrazić apki, gdzie każda z warstw może jedynie odnieść się do warstwy pod nią. T.j. UI tylko może odnieść się do Application i łapy precz od Infra czy Domain.

Warstwy wgl nie powinny się odnosić do siebie. Jedna warstwa przekazuje innej warstwie dane i czeka na wynik – cała interakcja.

Mi to brzmi jak wyjątek albo przynajmniej boolean na steroidach.

if ($validator->validate($data) ) {
    var_dump($validator->getErrors());
}

 

+1 głos
odpowiedź 1 lutego 2019 przez ShiroUmizake Nałogowiec (46,300 p.)
Ja bym zrobił zwrotkę do kontrolera i tam obsłużył wyjątek. Bo potem się zakopiesz w try/catch :P
komentarz 1 lutego 2019 przez `Krzychuu Stary wyjadacz (13,940 p.)
W Symfony można rzucać wyjątkami bez try/catch
1
komentarz 1 lutego 2019 przez HaKIM Szeryf (87,590 p.)

W Symfony można rzucać wyjątkami bez try/catch

Co z tego? Wszędzie możesz rzucać bez try catch. Try catch nie ma nic do rzucania wyjątkami, tylko ich przechwytywania.

Imo. głos w dół niezasłużony, bo ShiroUmizake podpowiedział b. dobrze.

1
komentarz 1 lutego 2019 przez `Krzychuu Stary wyjadacz (13,940 p.)
Szczerze to o tym nie widziałem, myślałem nad napisaniem event lisntener do przechwytywania błędu.

Ps. Głos w dół nie był ode mnie
1
komentarz 1 lutego 2019 przez HaKIM Szeryf (87,590 p.)
Ja sobie tak to załatwiłem u siebie:

https://github.com/HaKIMus/smartphones/blob/develop/src/Controller/Api/Smartphones/SmartphonesApi.php

Jestem bardzo dumny z tego kodzika, bo wszystkie try i catch wyizolowałem do handlera. :)

A tu sam exception handler:

https://github.com/HaKIMus/smartphones/blob/develop/src/Controller/Api/Handlers/SmartphonesApiHandler.php

W następnej wersji powinienem dodać do niego abstrakcje, po której będą rozszerzały wszystkie controller handlery aby uzyskać dostęp do chronionych metod t.j. returnResponse itp.
komentarz 1 lutego 2019 przez `Krzychuu Stary wyjadacz (13,940 p.)
Fajnie to wygląda, jakbym miał napisany handler to wtedy nie byłoby problemu z używaniem wyjątków w serwisach?, Rzucanie wyjątków można zaliczyć do logiki czy takie sprawy bardziej powinny być w kontrolerze ?
1
komentarz 1 lutego 2019 przez HaKIM Szeryf (87,590 p.)

Nie ma żadnego problemu z używaniem wyjątków gdziekolwiek, gdzie jest to potrzebne. Grunt, żeby je gdzieś obsłużyć, bo inaczej User dostanie Internal 500 na twarz a w gorszym wypadku, przy źle skonfigurowanej produkcji, exception ze wszystkimi informacjami.

Rzucanie wyjątków można zaliczyć do logiki czy takie sprawy bardziej powinny być w kontrolerze ?

Jest to logika, ale to tak jakbyś się czepiał ifów czy loopów w templatkach. Koszt wyizolowania tych rzeczy jest większy, niżeli trzymanie tego w kontrolerze.

komentarz 1 lutego 2019 przez `Krzychuu Stary wyjadacz (13,940 p.)
Dziękuje za pomoc i cenne informacje :)
1
komentarz 1 lutego 2019 przez HaKIM Szeryf (87,590 p.)

Tak nawiasem mówiąc to w tym kodzie:

throw new HttpException(400, "Nazwa zajęta!");

nadaje się prędzej 409 statusik.

No i ja polecam Ci korzystać z Response::HTTP_* - Jeśli lookniesz wgłąb klasy Response to zauważysz, że mają oni tam listę constów ze http statusami.

class Response
{
    const HTTP_CONTINUE = 100;
    const HTTP_SWITCHING_PROTOCOLS = 101;
    const HTTP_PROCESSING = 102;            // RFC2518
    const HTTP_EARLY_HINTS = 103;           // RFC8297
    const HTTP_OK = 200;
    const HTTP_CREATED = 201;
    const HTTP_ACCEPTED = 202;
    const HTTP_NON_AUTHORITATIVE_INFORMATION = 203;
    const HTTP_NO_CONTENT = 204;
    const HTTP_RESET_CONTENT = 205;
    const HTTP_PARTIAL_CONTENT = 206;
    const HTTP_MULTI_STATUS = 207;          // RFC4918
    const HTTP_ALREADY_REPORTED = 208;      // RFC5842
    const HTTP_IM_USED = 226;               // RFC3229
    const HTTP_MULTIPLE_CHOICES = 300;
    const HTTP_MOVED_PERMANENTLY = 301;
    const HTTP_FOUND = 302;
    const HTTP_SEE_OTHER = 303;
    const HTTP_NOT_MODIFIED = 304;
    const HTTP_USE_PROXY = 305;
    const HTTP_RESERVED = 306;
    const HTTP_TEMPORARY_REDIRECT = 307;
    const HTTP_PERMANENTLY_REDIRECT = 308;  // RFC7238
    const HTTP_BAD_REQUEST = 400;
    const HTTP_UNAUTHORIZED = 401;
    const HTTP_PAYMENT_REQUIRED = 402;
    const HTTP_FORBIDDEN = 403;
    const HTTP_NOT_FOUND = 404;
    const HTTP_METHOD_NOT_ALLOWED = 405;
    const HTTP_NOT_ACCEPTABLE = 406;
    const HTTP_PROXY_AUTHENTICATION_REQUIRED = 407;
    const HTTP_REQUEST_TIMEOUT = 408;
    const HTTP_CONFLICT = 409;
    const HTTP_GONE = 410;
    const HTTP_LENGTH_REQUIRED = 411;
    const HTTP_PRECONDITION_FAILED = 412;
    const HTTP_REQUEST_ENTITY_TOO_LARGE = 413;
    const HTTP_REQUEST_URI_TOO_LONG = 414;
    const HTTP_UNSUPPORTED_MEDIA_TYPE = 415;
    const HTTP_REQUESTED_RANGE_NOT_SATISFIABLE = 416;
    const HTTP_EXPECTATION_FAILED = 417;
    const HTTP_I_AM_A_TEAPOT = 418;                                               // RFC2324
    const HTTP_MISDIRECTED_REQUEST = 421;                                         // RFC7540
    const HTTP_UNPROCESSABLE_ENTITY = 422;                                        // RFC4918
    const HTTP_LOCKED = 423;                                                      // RFC4918
    const HTTP_FAILED_DEPENDENCY = 424;                                           // RFC4918

    [...]
}

https://tools.ietf.org/html/draft-ietf-httpbis-p2-semantics-18#section-7.4.10

komentarz 1 lutego 2019 przez `Krzychuu Stary wyjadacz (13,940 p.)
Dziękuje, faktycznie lepiej to będzie wyglądać
+1 głos
odpowiedź 1 lutego 2019 przez Ehlert Ekspert (212,670 p.)
Osobiście nie aż tak często plącze się w try catch, a wyjątkami się rzuca. Kluczowe mogą być dla Ciebie: EventSubscriber oraz event Kernel.EXCEPTION

Podobne pytania

0 głosów
1 odpowiedź 143 wizyt
pytanie zadane 8 marca 2021 w PHP przez michal_php Stary wyjadacz (13,700 p.)
0 głosów
1 odpowiedź 93 wizyt
pytanie zadane 30 września 2020 w PHP przez User007 Bywalec (2,400 p.)
0 głosów
2 odpowiedzi 155 wizyt
pytanie zadane 3 września 2018 w PHP przez BetBet Użytkownik (550 p.)

92,570 zapytań

141,422 odpowiedzi

319,643 komentarzy

61,958 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!

...