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

Symfony - Pytanie dotyczące trasowania

Object Storage Arubacloud
0 głosów
650 wizyt
pytanie zadane 15 maja 2016 w PHP przez GaCeL Dyskutant (7,500 p.)
edycja 15 maja 2016 przez GaCeL

Cześć, jak mam wstawić format datetime do adresu url który wpisuje w przeglądarce? Chodzi mi o startDate i endDate

 

<?php

namespace AppBundle\Controller;

use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Annotation\Route;
use AppBundle\Entity\Transport;

class TransportController extends Controller
{
    /**
     * @Route("/add/{user}/{startCity}/{endCity}/{cargo}/{distance}/{weight}/{damage}/{fuel}/{fueled}/{country}/{score}/{transportId}/{screenshot}/{startDate}/{endDate}/", defaults={"status" = 0})
     */
    public function addAction($user, $startCity, $endCity, $cargo, $distance, $weight, $damage, $fuel, $fueled, $country, $score, $transportId, $screenshot, $startDate, $endDate)
    {
        $transport = new Transport();

        $transport->setUser($user);
        $transport->setStartCity($startCity);
        $transport->setEndCity($endCity);
        $transport->setCargo($cargo);
        $transport->setDistance($distance);
        $transport->setWeight($weight);
        $transport->setDamage($damage);
        $transport->setFuel($fuel);
        $transport->setFueled($fueled);
        $transport->setCountry($country);
        $transport->setScore($score);
        $transport->setTransportId($transportId);
        $transport->setScreenshot($screenshot);
        $transport->setStatus(0);
        $transport->setStartDate($startDate);
        $transport->setEndDate($endDate);

        $em = $this->getDoctrine()->getManager();
        $em->persist($transport);
        $em->flush();

        return new Response("Dodano nowy transport o identyfikatorze: ".$transport->getTransportId());
    }
}

 

komentarz 16 maja 2016 przez event15 Szeryf (93,790 p.)

Pan to chyba Factory Method, Prototype lub Buildera nie zna, co? :)

Ładnie się zaczyna - tworzysz instancję obiektu Transport - jednak to nie jest miejsce na takie coś. Powinieneż stworzyć sobie jakąś prostą fabrykę, która tu by miała wywołanie: 

<?php

$transport = new FactoryTransport();

$transport->build(parametry);

I tyle.

Jednak gdyby się jeszcze bardziej uczepić i pobawić w upiększanie uelastycznianie i SOLIDne rzeczy, to warto zastosować zaczątek CQRS czyli zwykłego Commanda:

<?php
$newTransport = new AddTransportCommand(parametry);
$newTransport->execute();

Przy tworzeniu instancji byś wywoływał metody odpowiednio ustawiające klasę, a przy execute byś zadbał o obsługę tego oraz wrzucenie do repozytorium agregatu. 

(Dałem tę odpowiedź w komentarzu bo nie traktuje bezpośrednio o tym, co potrzebujesz a uznałem, że warto byś wiedział wink )

komentarz 16 maja 2016 przez GaCeL Dyskutant (7,500 p.)
Jak zaimportować mapowanie w rozszerzeniu .yml do encji Transport?
komentarz 17 maja 2016 przez event15 Szeryf (93,790 p.)
komentarz 17 maja 2016 przez GaCeL Dyskutant (7,500 p.)

A validation.yml, jak zaimportować do wybranego bundle?

3 odpowiedzi

+1 głos
odpowiedź 16 maja 2016 przez event15 Szeryf (93,790 p.)

Moim zdaniem tworzysz błędne rozwiązanie prostego problemu.

Z jakiego powodu do linku wrzucasz:

  • user
  • startCity
  • endCity
  • cargo
  • distance
  • weight
  • damage
  • fuel
  • fueled
  • country
  • score
  • transportId
  • screenshot
  • startDate
  • endDate

?

Cała masa gówna niepotrzebnego w linku. 

Co nam mówi ten link? 

Masz metodę o nazwie addAction() więc domyślam się, że chcesz dodać coś lub wszystko (bo nazwa kontrolera nie mówi mi nic o tym co chcesz dodać - co jest kiepską praktyką. Powinno się stosować nazwy metod i zmiennych, które mówią nam jak najwięcej o kodzie i jego funkcji):

Nie wiem dlaczego zaczynasz kontroler tej akcji od słowa "user" - to od razu daje sygnał, że "dla użytkownika" wykonaj akcję. 

Reszta danych może być przesyłana za pomocą klas Request i Response:

Symfony\Component\HttpFoundation\Request
Symfony\Component\HttpFoundation\Response

I w zależności od potrzeby wykonać odpowiednie zapytanie ze strony frontu w postaci jakiegoś POSTa. 

Poza tym warto byś zainteresował się RESTem:

Oraz HATEOAS (de facto fundament resta):

 

Ogólnie o REST możesz poczytać: http://restcookbook.com/

Odnośnie Twojego problemu, rozumiem, że setery, które masz w kontekście dat to jakieś obiekty DateTime()? Jeśli chcesz je odbierać z linka to są one traktowane jako tekst i musisz je po prostu przetworzyć na obiekt typu DateTime. 

Nie powinieneś w tym miejscu też wpychać bazy danych i wykonywać na niej jakiś akcji - to zła praktyka. W tym kontrolerze mieszasz akcje - które powinny być atomowe i jasno mówić nam jakie jest ich zadanie (metody nie powinny mieć więcej niż 5 wierszy w kontrolerze), logikę dziedziny stosujesz w kontrolerach a nie w oddzielnym modelu, który powinien to wszystko samodzielnie obsługiwać - czyli tak naprawdę w przypadku symfony powinien istnieć osobny Bundle - lub raczej zupełnie odseparowany kawałek kodu od całego symfony, odpowiedzialny wyłącznie za dziedzinę - czyli za wszystko związane z tym transportem, w tym klasy walidacyjne i adaptery dla repozytoriów. Dodatkowo wkładasz tutaj kod infrastruktury, który nie powinien być mieszany z kodem kontrolera, a tym bardziej z kodem logiki dziedziny. 

Gdy zwracasz za pomocą Response() to tak estetycznie raczej lepiej jest dać zwykłą okejkę niż pisać co się udało. 

Chciałbym zwrócić uwagę, że nie widze w tym kodzie nawet wzmianki o tym, że gdzieś dokonujesz walidacji zmiennych otrzymywanych od użyszkodznika. 

komentarz 16 maja 2016 przez event15 Szeryf (93,790 p.)

"/add/{user}/{startCity}/{endCity}/{cargo}/{distance}/{weight}/{damage}/{fuel}/{fueled}/{country}/{score}/{transportId}/{screenshot}/{startDate}/{endDate}/

Własnie wyobraziłem sobie jak wygląda ten link gdy wszystko się do niego wrzuci:

/add/event15/Gdańsk/Oświęcim/jedzenie/800/49000/100/5/500/Polska/12034/adf(lKl!@#$j234fa094r5/_preview.png/16-05-2016/20-05-2016/ 

Co mnie przekonuje, że brniesz w coś ze złym podejściem. 

Jeśli masz więcej rzeczy niż transport, które możesz dodać to przede wszystkim wywal z linku słówko "add" które jest niepotrzebne gdy używasz restowego api - wystarczy informacja, że potrzebujesz POST. Zauważ - używając metody POST nie będziesz mieć linku. Jednak moim zdaniem to nie powinien być problem. 

Masz sobie widok, który jest pod adresem domena.pl/transport

Pod tym linkiem masz dostępne api: POST który jest /transport POST i jsonem wysyłane dane które potrzebujesz - ta akcja dodaje transport

Gdy potrzebujesz pobrać ostatni transport:

/transport/last

Gdy potrzebujesz pobrać transport z przedziału datowego:

/transport/criteria/16-05-2016:20-05-2016/ 

(na przykład) zamiast criteria może być "search"

Gdy potrzebujesz wyświetlic konkretny transport:

/transport/{transportId}

Gdy potrzebujesz zmodyfikować konkretny transport:

/transport/{transportId} PATCH lub PUT z danymi. 

Nie wgryzam się w szczegóły bo jest dużo teorii odnośnie tego kiedy używać patch a kiedy put.

Do wgrywania zdjęć warto zrobić sobie w ogóle osobną obsługe api. Na przykład /api/file Dzięki temu możesz w osobnym miejscu twrorzyć rozwiązania wyłącznie dla plików ze zdjęciami - obsługe jpg, gif bmp czy png. Ich cropowanie, nadawanie im różnych masek czy nie wiem - rozpoznawanie twarzy. Wtedy nie są one związane z samym transportem - a pewnie masz w innych miejscach w "projekcie" też obsługe obrazków. 

komentarz 16 maja 2016 przez GaCeL Dyskutant (7,500 p.)
Ale spokojnie, @Route(i milion zmiennych) stworzyłem tylko po to żeby pobawić się doctrine, zobaczyć jak działa, zrozumieć a wy mi tu piszecie że zrobiłem milion błędów, tak wiem, zrobiłem ale chciałem tylko zrozumieć doctrine, a później zrobić to tak jak należy. Ale dziękuje również za podpowiedzi, i rozwiązania.
komentarz 16 maja 2016 przez event15 Szeryf (93,790 p.)
Zabawa z doctrine powinna mieć miejsce w Repozytorium a konfiguracja encji w plikach yml i generalnie nie powinno się stosować adnotacji ponieważ php tego natywnie nie obsługuje i zaśmieca tylko kod.

Takie sprawy powinny być robione za pomocą plików konfiguracyjnych - YAML jest najlepszy.

Doctrine, jak i Symfony udostępniają możliwość tworzenia konfiguracji w plikach yml. Pozwalają na korzystanie z ormów wszędzie, aczkolwiek dobrą praktyką jest wydzielenie warstwy infrastruktury a do repo wrzucałbyś odpowiednio spreparowaną encję.
0 głosów
odpowiedź 16 maja 2016 przez SyntaxError Pasjonat (17,170 p.)
A pokaż te encje Transport.
komentarz 16 maja 2016 przez efiku Szeryf (75,160 p.)
Mógłby ją przekazać jako argument kontrolera, Symfony powinno samo wstrzyknac odpowiednie dane.
komentarz 16 maja 2016 przez GaCeL Dyskutant (7,500 p.)
<?php

namespace AppBundle\Entity;

use Doctrine\ORM\Mapping as ORM;

/**
 * @ORM\Entity
 * @ORM\Table(name="transports")
 */
class Transport
{
  /**
   * @ORM\Column(type="integer")
   * @ORM\Id
   * @ORM\GeneratedValue(strategy="AUTO")
   */
  private $id;
  
  /**
   * @ORM\Column(type="string")
   */
  private $user;

  /**
   * @ORM\Column(type="string")
   */
  private $startCity;

  /**
   * @ORM\Column(type="string")
   */
  private $endCity;

  /**
   * @ORM\Column(type="string")
   */
  private $cargo;

  /**
   * @ORM\Column(type="integer")
   */
  private $distance;

  /**
   * @ORM\Column(type="integer")
   */
  private $weight;

  /**
   * @ORM\Column(type="integer")
   */
  private $damage;

  /**
   * @ORM\Column(type="integer")
   */
  private $fuel;

  /**
   * @ORM\Column(type="integer")
   */
  private $fueled;

  /**
   * @ORM\Column(type="string")
   */
  private $country;

  /**
   * @ORM\Column(type="integer")
   */
  private $score;

  /**
   * @ORM\Column(type="string")
   */
  private $transportId;

  /**
   * @ORM\Column(type="string")
   */
  private $screenshot;

  /**
   * @ORM\Column(type="integer")
   */
  private $status;

  /**
   * @ORM\Column(type="datetime")
   */
  private $startDate;

  /**
   * @ORM\Column(type="datetime")
   */
  private $endDate;

    /**
     * Get id
     *
     * @return integer 
     */
    public function getId()
    {
        return $this->id;
    }

    /**
     * Set user
     *
     * @param string $user
     * @return Transport
     */
    public function setUser($user)
    {
        $this->user = $user;

        return $this;
    }

    /**
     * Get user
     *
     * @return string 
     */
    public function getUser()
    {
        return $this->user;
    }

    /**
     * Set startCity
     *
     * @param string $startCity
     * @return Transport
     */
    public function setStartCity($startCity)
    {
        $this->startCity = $startCity;

        return $this;
    }

    /**
     * Get startCity
     *
     * @return string 
     */
    public function getStartCity()
    {
        return $this->startCity;
    }

    /**
     * Set endCity
     *
     * @param string $endCity
     * @return Transport
     */
    public function setEndCity($endCity)
    {
        $this->endCity = $endCity;

        return $this;
    }

    /**
     * Get endCity
     *
     * @return string 
     */
    public function getEndCity()
    {
        return $this->endCity;
    }

    /**
     * Set cargo
     *
     * @param string $cargo
     * @return Transport
     */
    public function setCargo($cargo)
    {
        $this->cargo = $cargo;

        return $this;
    }

    /**
     * Get cargo
     *
     * @return string 
     */
    public function getCargo()
    {
        return $this->cargo;
    }

    /**
     * Set distance
     *
     * @param integer $distance
     * @return Transport
     */
    public function setDistance($distance)
    {
        $this->distance = $distance;

        return $this;
    }

    /**
     * Get distance
     *
     * @return integer 
     */
    public function getDistance()
    {
        return $this->distance;
    }

    /**
     * Set weight
     *
     * @param integer $weight
     * @return Transport
     */
    public function setWeight($weight)
    {
        $this->weight = $weight;

        return $this;
    }

    /**
     * Get weight
     *
     * @return integer 
     */
    public function getWeight()
    {
        return $this->weight;
    }

    /**
     * Set damage
     *
     * @param integer $damage
     * @return Transport
     */
    public function setDamage($damage)
    {
        $this->damage = $damage;

        return $this;
    }

    /**
     * Get damage
     *
     * @return integer 
     */
    public function getDamage()
    {
        return $this->damage;
    }

    /**
     * Set fuel
     *
     * @param integer $fuel
     * @return Transport
     */
    public function setFuel($fuel)
    {
        $this->fuel = $fuel;

        return $this;
    }

    /**
     * Get fuel
     *
     * @return integer 
     */
    public function getFuel()
    {
        return $this->fuel;
    }

    /**
     * Set fueled
     *
     * @param integer $fueled
     * @return Transport
     */
    public function setFueled($fueled)
    {
        $this->fueled = $fueled;

        return $this;
    }

    /**
     * Get fueled
     *
     * @return integer 
     */
    public function getFueled()
    {
        return $this->fueled;
    }

    /**
     * Set country
     *
     * @param string $country
     * @return Transport
     */
    public function setCountry($country)
    {
        $this->country = $country;

        return $this;
    }

    /**
     * Get country
     *
     * @return string 
     */
    public function getCountry()
    {
        return $this->country;
    }

    /**
     * Set score
     *
     * @param integer $score
     * @return Transport
     */
    public function setScore($score)
    {
        $this->score = $score;

        return $this;
    }

    /**
     * Get score
     *
     * @return integer 
     */
    public function getScore()
    {
        return $this->score;
    }

    /**
     * Set transportId
     *
     * @param string $transportId
     * @return Transport
     */
    public function setTransportId($transportId)
    {
        $this->transportId = $transportId;

        return $this;
    }

    /**
     * Get transportId
     *
     * @return string 
     */
    public function getTransportId()
    {
        return $this->transportId;
    }

    /**
     * Set screenshot
     *
     * @param string $screenshot
     * @return Transport
     */
    public function setScreenshot($screenshot)
    {
        $this->screenshot = $screenshot;

        return $this;
    }

    /**
     * Get screenshot
     *
     * @return string 
     */
    public function getScreenshot()
    {
        return $this->screenshot;
    }

    /**
     * Set status
     *
     * @param integer $status
     * @return Transport
     */
    public function setStatus($status)
    {
        $this->status = $status;

        return $this;
    }

    /**
     * Get status
     *
     * @return integer 
     */
    public function getStatus()
    {
        return $this->status;
    }

    /**
     * Set startDate
     *
     * @param \DateTime $startDate
     * @return Transport
     */
    public function setStartDate($startDate)
    {
        $this->startDate = $startDate;

        return $this;
    }

    /**
     * Get startDate
     *
     * @return \DateTime 
     */
    public function getStartDate()
    {
        return $this->startDate;
    }

    /**
     * Set endDate
     *
     * @param \dateTime $endDate
     * @return Transport
     */
    public function setEndDate(\dateTime $endDate)
    {
        $this->endDate = $endDate;

        return $this;
    }

    /**
     * Get endDate
     *
     * @return \dateTime 
     */
    public function getEndDate()
    {
        return $this->endDate;
    }
}

 

komentarz 16 maja 2016 przez event15 Szeryf (93,790 p.)

Ło matko. 

https://gist.github.com/event15/d79900af46fef424d5cb66f860bcece2

To teraz pacz:

Tworzysz 16 pól. W tym id i transportId się duplikują (chyba, że się mylę).

Teraz zobacz na logikę swojego zachowania. Tworzysz prywatne pola, następnie tworzysz publiczne akcesory do niej. Czyli równie dobrze możesz zrobić te wszystkie pola jako publiczne i wywalić 197 wierszów nadmiarowego kodu. 

W ogóle nie myślałeś nad tym, co zamierzasz zrobić. Stworzyłeś encję transport i wrypałeś tam ogromny śmietnik. 

Co ta klasa ma robić w ogóle?

class Transport
{
    // Identyfikatory
    private $id;
    private $user; // userId
    private $transportId;

    // Lokalizacje i odległości
    private $country;
    private $startCity;
    private $endCity;
    private $distance;

    // Daty
    private $startDate;
    private $endDate;

    // O ładunku
    private $cargo; // o ładunku
    private $weight;
    private $damage;

    // O transporterze
    private $fuel;
    private $fueled;

    // Jakieś punkty
    private $score;

    // czy potrzebne?
    private $screenshot;
    private $status;

}

Tutaj masz pole do popisu. Przede wszystkim powinienes zastanowić się czy rzeczywiście w tym miejscu potrzebujesz ID usera. Bo mam nadzieję, że nie potrzebujesz całej instacji. Nie musisz robić osobnego ID dla klasy i osobnego ID dla transportu. Doctrine to załatwia dla Ciebie. 

Odnośnie lokalizacji itp. to powinna być osobna encja City, którą byś tu wrzucił przez jakieś Dependency Injection. Coś jak funkcja(CityInterface $newCity). W niej byś oprogramował odpowienie metody, mógłbyś walidować dane w osobnej klasie. 

Daty możesz załatwić jakąś arrayką, iteratorem itp. 

Dane ładunku są jako ValueObject, ewentualnie jeśli będziesz potrzebował to jakoś bardziej rozbudowywać i te ładunku będą miały zdefiniowane jakieś działanie to kolejna encja. 

Transporter to w tym przypadku moze być jako VO i odnośnie screenschota to powinno być to w innym miejscu a tutaj tylko Dependency Injection do tego. 

Przede wszystkim encja to nie tylko getery i setery. To co tutaj dałeś to bardziej wygląda na DTO (Data Transfer Object), jednak nie masz żadnej fabryki do tworzenia tych obiektów wiec po prostu tak to zrobiłeś. 

W tej encji powinno byc zachowanie - może ona być agregatem jeśli jest to kluczowe w tej dziedzinie. Jeśli jest agregatem to ona ma zachowania odpowiedzialne za przeniesienie ładunku, załadowanie, rozładowanie, i tym podobne. 

Naprawdę, zachęcam Cie do poczytania o tych kilku rzeczach:

  • Command Pattern
  • Factory Method Pattern (albo Builder lub Abstract Factory) - wszystkie są podobne i łatwo ogarnąć
  • Repository Pattern

http://zawarstwaabstrakcji.pl/20151020-save-repository-from-save/

http://zawarstwaabstrakcji.pl/20151008-jeste-buildere/

http://zawarstwaabstrakcji.pl/20151102-avatar-uzytkownika-upload-plikow/

Jest dobrze opisane to, o czym mówię. Nie jest do długa lektura. 

komentarz 16 maja 2016 przez GaCeL Dyskutant (7,500 p.)

W dokumentacji są takie przykłady, więc aby zrozumieć działanie Doctrine zrobiłem kod dokładnie na wzór tego z dokumentacji.


transportId, to będzie identyfikator transportu np: XXYX/XYX/XZ123/PL
status, jeżeli 0 to transport jest w weryfikacji a jeżeli 1 to transport jest zatwierdzony.

W encji Transport potrzebuję tylko getery i setery.

komentarz 16 maja 2016 przez event15 Szeryf (93,790 p.)
Chcesz pisać gówno to pisz.
komentarz 16 maja 2016 przez event15 Szeryf (93,790 p.)
Zrób z miejsca wszystkie pola publiczne wtedy bedziesz miec to samo działanie i tylko 30 linii kodu a nie 300. Oszczęðność czasu, liczby wierszy i myślenia. A jak się uprzesz to już __get() i __set().
–3 głosów
odpowiedź 15 maja 2016 przez natrov Gaduła (3,970 p.)
Użyć metody GET.

?startDate=123456789&&endDate=987654321

Podobne pytania

0 głosów
1 odpowiedź 164 wizyt
pytanie zadane 30 kwietnia 2016 w PHP przez GaCeL Dyskutant (7,500 p.)
0 głosów
1 odpowiedź 428 wizyt
pytanie zadane 9 maja 2019 w PHP przez Anon LVL 1000 Użytkownik (690 p.)
0 głosów
0 odpowiedzi 90 wizyt
pytanie zadane 6 kwietnia 2018 w PHP przez Neronys Bywalec (2,090 p.)

92,576 zapytań

141,426 odpowiedzi

319,652 komentarzy

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

...