DiscoverPlaces Raport #3

Od ostatniego raportu minęły trzy dni. W tym czasie trochę udało się ogarnąć. W końcu konto na githubie nie świeci pustkami i pojawiają się jakieś commity.

W ramach przypomnienia ten wpis dotyczy projektu opisanego tutaj.

 Co zostało zrobione?

API obecnie jest prawie skończone, do zrobienia zostało tylko pobieranie listy wszystkich wiadomości na podstawie lokalizacji. Lista tego co już jest wykonane:

  • Dodaj wiadomość(tekst, zdjęcie, video, zasięg(kilka wartości do wyboru))
  • Dodaj komentarz(tekst, zdjęcie, video)
/**
 * @param Request $request
 * @return Response
 */
public function createMessageAction(Request $request)
{
    $message = new Message();

    $form = $this->createForm(MessageType::class, $message);
    $form->handleRequest($request);

    if ($form->isSubmitted() && $form->isValid()) {
        $this->get('photo.uploader')->upload($message, $this->getParameter('message_uploads_dir'));
        $this->get('video.uploader')->upload($message, $this->getParameter('message_uploads_dir'));

        $this->get('resource.manager')->save($message);

        $view = $this->view(null, 201);
        return $this->handleView($view);
    }

    $errors = $this->get('utils.form_error_parser')->getErrors($form);
    $view = $this->view($errors, 400);
    return $this->handleView($view);
}
/**
     * @param Request $request
     * @param Message $message
     * @return Response
     *
     * @ParamConverter("message", class="AppBundle:Message", options={"id" = "message_id"})
     */
    public function createCommentAction(Request $request, Message $message)
    {
        $comment = new Comment();

        $form = $this->createForm(CommentType::class, $comment);
        $form->handleRequest($request);

        if ($form->isSubmitted() && $form->isValid()) {
            $this->get('photo.uploader')->upload($comment, $this->getParameter('comment_uploads_dir'));
            $this->get('video.uploader')->upload($comment, $this->getParameter('comment_uploads_dir'));

            $comment->setMessage($message);

            $comment = $this->get('resource.manager')->save($comment);

            $view = $this->view(null, 201);
            return $this->handleView($view);
        }

        $errors = $this->get('utils.form_error_parser')->getErrors($form);
        $view = $this->view($errors, 400);
        return $this->handleView($view);
    }

Powyżej przedstawione zostały metody odpowiedzialne za realizację dodawania odpowiednio wiadomości oraz komentarza. W metodzie createCommentAction() użyty został ParamConverter. Jest to dosyć użyteczna adnotacja pozwalająca od razu mapować parametry z Requesta i pobierać żądany obiekt. Całość kodu można znaleźć na githubie. Oraz poniżej testy funkcjonalne:

public function testCreateMessage()
{
    $client = self::createClient();
    $fixturesPath = $client->getContainer()->getParameter('kernel.root_dir').'/../tests/AppBundle/fixtures/';
    copy($fixturesPath.'img.jpg', $fixturesPath.'test.jpg');

    $photo = new UploadedFile(
        $fixturesPath.'test.jpg',
        'test.jpg'
    );

    $client->request(
        'POST',
        '/front/api/message', [
            'message' => [
                'content' => 'test',
                'latitude' => 50,
                'longitude' => 50,
                'scope' => 1,
            ]
        ], [
            'message' => [
                'photo' => $photo
            ]
        ]
    );

    $this->assertEquals(201, $client->getResponse()->getStatusCode());
}

 

public function testCreateComment()
{
    $client = self::createClient();
    $fixturesPath = $client->getContainer()->getParameter('kernel.root_dir').'/../tests/AppBundle/fixtures/';
    copy($fixturesPath.'img.jpg', $fixturesPath.'test.jpg');

    $photo = new UploadedFile(
        $fixturesPath.'test.jpg',
        'test.jpg'
    );

    $client->request(
        'POST',
        '/front/api/message/1/comment', [
            'comment' => [
                'content' => 'test'
            ]
        ], [
            'comment' => [
                'photo' => $photo
            ]
    ]
    );

    $this->assertEquals(201, $client->getResponse()->getStatusCode());
}

Na obecną chwilę będą tylko skromne testy funkcjonalne. Jak całość będzie gotowa i jakoś się to przyjmie to wtedy można myśleć na rozbudową i pisaniem szerszych testów, póki co szkoda marnować czasu.

Poniżej przedstawię kilka uwag jakie nasunęły mi się podczas pisania tego kodu. Pozostałe raporty też będę pisał w ten sposób, aby to nie był suchy kod i opisanie co zostało zrobione. Wiadomo, że w pracy programisty codziennie spotykamy się z sytuacjami, gdzie coś nie działa, mamy jakiś problem, więc warto podzielić się problemem i wskazówkami jak go rozwiązać.

413 Request Entity Too Large

Błąd Nginxa przy wysyłaniu zbyt dużego Requesta, domyślnie jest to 2MB, aby temu zaradzić do konfiguracji Nginxa w sekcji http, server lub location dodajemy na przykład:

client_max_body_size 100M;

Testowanie uploadu pliku

Przy pisaniu testu, w którym uploadowany będzie na serwer przykładowy plik z katalogu tests/AppBundle/fixtures/img.jpg działo się tak, że ten plik nie był kopiowany tylko przenoszony. Ten problem rozwiązuje linijka:

copy($fixturesPath.'img.jpg', $fixturesPath.'test.jpg');

 Połączenie z kontenerem bazy danych

mysql:
    image: mysql
    ports:
      - "8003:3306"

Mając taki skonfigurowany kontener dockerowy z bazą danych mysql, aby połączyć się do niego z tak zwanego hosta, czyli systemu gospodarza, używamy w tym celu hosta: localhost oraz portu 8003, lub virtual hosta np. discoverplaces.dev, gdzie jego konfiguracja (/etc/hosts na Linuxie) wygląda tak:

127.0.0.1 discoverplaces.dev

Tutaj takie jeszcze wspomnienie, że nie mając skonfigurowanego phpmyadmin w dockerze, chcąc na szybko połączyć się z bazą danych trafiłem na bardzo lekką i prostą aplikację Sqlectron, która doskonale sprawdza się do podstawowych zastosowań typu: sprawdzenie co  tam zawiera się w jakiejś tabeli.

Konfiguracja środowiska testowego

Konfiguracja środowiska testowego symfony znajduje się w pliku app/config/config_test.yml, gdzie wrzuciłem również konfigurację dla osobnej bazy do testów, aby nie zaśmiecać środowiska deweloperskiego:

doctrine:
    dbal:
        host:     "%test_database_host%"
        port:     "%test_database_port%"
        dbname:   "%test_database_name%"
        user:     "%test_database_user%"
        password: "%test_database_password%"

Użyte parametry ustawiane są natomiast w app/config/parameters.yml wraz z pozostałymi. Stworzyłem również Fixtures, do załadowania jednej wiadomości do bazy danych, tak aby wykonywane testy przechodziły, ponieważ komentarze można dodać tylko do istniejącej już wiadomości. Więc aby przechodziły testy, najpierw baza danych wypełniania jest tą jedną wiadomością i gdy wykonywany jest test dodawania komentarza, to zostaje on przypisany do tej wiadomości. Dzięki temu niezależnie od kolejności wykonywania testów, powinno wszystko być poprawnie. Poniżej znajdują się dwie linijki odpowiadające kolejno za załadowanie Fixtures do deweloperskiej  oraz testowej bazy danych:

php bin/console d:f:l
php bin/console d:f:l --env=test

Co dalej?

Kolejną rzeczą jak już wspomniałem będzie utworzenie kolejnego endpointa, pozwalającego pobrać wiadomości dla określonej lokalizacji. Po wykonaniu tego, bardzo proste API, będzie gotowe do użycia. Następnie przejdę do tworzenia aplikacji komunikującej się z tym API.

Udostępnij: