Internet Engineering LAB 2 WSKAZÓWKA Domyślnie PHPStorm nie informuje o brakujących przestrzeniach nazw w adnotacja (adnotacja to intepretowany przez PHP komentarz zaczynający się od ). Można ten problem szybko rozwiązać poprzez instalację pluginu "PHP Annotations" i "PHP Toolbox". Plugin instalujemy poprzez wybór: File > Settings > Plugins > Browse Repository. Po instalacji pluginów i ponownym uruchomieniu PHPStorm, każda niezaimportowana adnotacja podświetli się na żółto, np. Aby zaimportować przestrzeń nazw, klikamy podświetlony blok, LEWY ALT + ENTER i wybieramy odpowiedni import, np. pozwoli na dodanie: use FOS\RestBundle\Controller\Annotations\Get; 1. Instalujemy MongoDB Community (pomiń ten krok w laboratorium) https://www.mongodb.com/download-center#community 2. Instalujemy Robomongo (pomiń ten krok w laboratorium) https://robomongo.org/download 3. Stwórz skrót do uruchamiania MongoDB (pomiń ten krok w laboratorium) Utwórz skrót do "C:\Program Files\MongoDB\Server\3.4\bin\mongod.exe" --dbpath [SCIEŻKA_BAZY] [SCIEŻKA_BAZY] to katalog gdzie fizycznie będzie przechowywana pliki bazy danych należy go dostosować do swoich potrzeb w laboratorium proponuje pulpit, np. "c:\program Files\MongoDB\Server\3.4\bin\mongod.exe" --dbpath=e:\mongodb\ Pamiętaj, że jeśli wybierzesz katalog na dysku C konieczne może być uruchomienie MongoDB z uprawnieniami administrator!
Uruchomienie Serwera MongoDB sprowadza się do uruchomienia utworzonego skrótu. Powinno pojawić się okno konsoli z informacją: [thread1] waiting for connections on port 27017 oznacza to, że serwer oczekuje na połączenie. Okno można zminimalizować. Zamknięcie okna wyłączy serwer MongoDB. 4. Uruchamiamy RoboMongo i testujemy połączenie do localhost bez autentykacji. a. Tworzymy bazę: z Menu kontekstowego na ikonie serwera Create Database i podać nazwę, np. projekt 5. Instalujemy bibliotekę PHP MongoDB (pomiń ten krok w laboratorium) a. https://pecl.php.net/package/mongodb Bibliotekę (plik dll) umieścić w katalogu ext w miejscu instalacji php, należy ściągnąć bibliotekę do odpowiedniej wersji PHP. W przypadku instalacji serwera WAMP z PHP 7 będzie to: 7.0 Thread Safe (TS) x64 Testowana była wersja 1.2.5 (1.2.6 też powinna działać) b. Konieczne jest dodanie obsługi MongoDB zarówno do konsolowej wersji PHP jak i tej obsługiwanej przez Apache, w tym celu: i. Wyedytować php.ini (c:\wamp64\bin\php\php7.0.10\php.ini) znajdź sekcję Dynamic Extensions i dodać wpis: extension=php_mongodb.dll ii. Korzystając z menu Wamp > PHP > php.ini znajdź sekcję Dynamic Extensions i dodać wpis: extension=php_mongodb.dll c. Zrestartować serwer Wamp! 6. Test poprawności: a. Uruchomić testową stronę WAMP (http://localhost ) i sprawdź, czy w sekcji "Loaded Extensions" znajduje się mongodb. 7. Zainstaluj biblioteki composera (tak jak na poprzednich zajęciach) a. alcaeus/mongo-php-adapter b. doctrine/mongodb-odm c. doctrine/mongodb-odm-bundle Możesz to zrobić również ręcznie z linii komend (będąc w katalogu projektu)
php composer.phar require [NAZWA_BIBLIOTEKI] 8. Konfiguracja symfony: a. Do app/autoload.php (przed return) dodać use Doctrine\ODM\MongoDB\Mapping\Driver\AnnotationDriver; AnnotationDriver::registerAnnotationClasses(); b. Do app/appkernel.php do tablicy $bundles dodać: new Doctrine\Bundle\MongoDBBundle\DoctrineMongoDBBundle() c. app/config/config.yml: doctrine_mongodb: connections: default: server: 'mongodb://localhost:27017' options: default_database: 'projekt' document_managers: default: auto_mapping: true Wartość parametru default_database musi być zgodny z wybrana nazwa bazy z punktu 4 9. s cache:clear dla szybkiej weryfikacji czy ciągle wszystko działa 10. W projekcie stwórz katalog Document (w src/appbundle) tam umieszczamy wszystkie klasy mapowane w bazie MongoDB a. Stwórz swój model (plik Book.php): namespace AppBundle\Document; use Doctrine\ODM\MongoDB\Mapping\Annotations as ODM; use MongoId; * * @ODM\Document class Book * @var MongoId $id * * @ODM\Id(strategy="AUTO") protected $id; * @var string * @ODM\Field(type="string") protected $title;
Zauważ, że wykorzystuje alias w dyrektywie use i jak się nim posługujemy w klasie. b. Dodaj gettery i setter: lewy ALT + INSERT > Getters and setters c. Stwórz kontroler w src\appbundle\controller (plik BookController.php) namespace AppBundle\Controller; use FOS\RestBundle\Controller\FOSRestController; use Symfony\Component\HttpFoundation\Request; use FOS\RestBundle\Controller\Annotations\Get; use FOS\RestBundle\Controller\Annotations\Post; use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route; use FOS\RestBundle\Controller\Annotations\Delete; use FOS\RestBundle\Controller\Annotations\View; class BookController extends FOSRestController * @Get("/") public function indexaction(request $request) d. Stwórz formularz src\appbundle\form\booktype.php: namespace AppBundle\Form; use Symfony\Component\Form\AbstractType; use Symfony\Component\Form\Extension\Core\Type\TextType; use Symfony\Component\Form\FormBuilderInterface; use Symfony\Component\OptionsResolver\OptionsResolver; class BookType extends AbstractType public function buildform(formbuilderinterface $builder, array $options) $builder ->add('title', TextType::class) ; public function configureoptions(optionsresolver $resolver) $resolver->setdefaults(array( 'data_class' => 'AppBundle\Document\Book', 'csrf_protection' => false // Bardzo ważne! ));
11. Za pomocą RoboMongo stwórz kolekcję Book (rozwiń drzewko swojej bazy, prawym na Collections > Create Collection). Nazwij ją Book Do kolekcji Book dodaj kilka dokumentów (prawym na Book > Insert Document), np. a. title: 'W pustyni i w puszczy' b. title: 'Pan Tadeusz' Wpisy te przydadzą nam się do debugowania kodu! 12. Wracamy do BookControler. a. Dodajemy odpowiednie klauzule use: use FOS\RestBundle\Controller\Annotations\Get; use FOS\RestBundle\Controller\Annotations\Post; use FOS\RestBundle\Controller\Annotations\Put; use FOS\RestBundle\Controller\Annotations\Delete; use FOS\RestBundle\Controller\Annotations\View; b. Dodajemy prefix dla kontrolera, dodając zaraz nad definicję kontrolera, adnotację: * @Route("book") class BookController extends FOSRestController Prefix routingu sprawia, że routing do każdej akcji kontrolera będzie poprzedzony podaną nazwą (w przykładzie: book) i nie trzeba podawać jej za każdym razem definiując routing dla akcji. c. Tworzymy metodę pomocniczą, zwracającą obiekt menadżera bazy danych: private function getdocumentmanager() return $this->get('doctrine_mongodb')->getmanager(); d. Poprawiamy metodę indexaction by zwracała wszystkie książki z bazy. * @Get("/", name="book_index") public function indexaction(request $request) $books = $dm->getrepository('appbundle:book')->findall(); return $books;
Za pomocą narzędzia postman wykonaj zapytanie GET: [ADRES]/app_dev.php/book/ Dodajemy metodę która zwraca pełne info o danej książce: * @Get("/get/id", name="book_get") public function getaction(request $request, string $id) $book = $dm->getrepository('appbundle:book')->find($id); if (!$book) throw $this->createnotfoundexception('book not found'); return $book; Metodę testujemy pod adresem: [ADRES]/app_dev.php/book/get/[ID] [ID] to id książki można go uzyskać, ze spisu książek lub aplikacji RoboMongo e. Wykorzystujemy formularz BookType aby użytkownik mógł podać dane dla nowej książki w treści zapytania. Poniższą metodę implementujemy w * @Put("/create", name="book_create") public function createaction(request $request) $book = new Book(); $form = $this->createform(booktype::class, $book); $form->submit($request->request->all()); if ($form->isvalid()) $dm->persist($book); $dm->flush(); return $book; return $form; Metodę testujemy podając w Postman url: [ADRES]/app_dev.php/book/create, ustawić metodę zapytania w Postman na PUT oraz podać dane w zakładce "Body" typu RAW z listy wybrać JSON. W okienku podać np. "title" : "Moja wlasna ksiazka"
f. Stwórz metodę do edycji (aktualizacji) książki o podanym ID (ID przekazane w parametrze) * @Post("/update/id", name="book_update") public function updateaction(request $request, $id) $book = $dm->getrepository('appbundle:book')->find($id); $form = $this->createform(booktype::class, $book); $form->submit($request->request->all()); if ($form->isvalid()) $dm->persist($book); $dm->flush(); return $book; return $form; Metodę testujemy pod url: [ADRES]/app_dev.php/book/update/[ID_KSIAZKI] ustawić typ zapytania w Postman na POST oraz podając dane w zakładce "Body" typu RAW z listy wybrać JSON. [ID_KSIAZKI] zamienić na dowolny ID książki z bazy. W okienku podać np. "title" : "Moja wlasna ksiazka 2" ID podajemy w postaci samego stringa, np. 58c833058356693ea8002dc5 który możemy odczytać w RoboMongo g. Usuwanie książki * @Delete("/id", name="book_delete") public function deleteaction(request $request, $id) $book = $dm->getrepository('appbundle:book')->find($id); if (!$book) throw $this->createnotfoundexception('selected book does not exist'); $dm->remove($book); $dm->flush(); return ["status" => "OK"]; Metodę testujemy pod adresem: [ADRES]/app_dev.php/book/[ID_KSIAZKI], typ zapytania ustawiamy na DELETE, pozostawiamy puste pole BODY.
h. Wyszukiwanie książki o danym tytule. Zwróć uwagę, na 3 alternatywne wersje. * @Get("/search/title", name="book_search") * @View(serializerGroups="list") public function searchaction(request $request, string $title) // Option 1. // $repository = $dm->getrepository('appbundle:book'); // $books = $repository->findby(['title' => $title]); // Option 2. // $books = $dm->createquerybuilder('appbundle:book')->field('title')- >equals($title)->getquery()->toarray(); // Option 3 LIKE using Regex $books = $dm->createquerybuilder('appbundle:book')->field('title')->equals(new MongoRegex('/.*'.$title.'.i'))->getQuery()->toArray(); if (!$books) throw $this->createnotfoundexception('book not found'); return $books; Metodę testujemy pod adresem: [ADRES]/app_dev.php/book/search/[TITLE] typ zapytania ustawiamy na GET, zamiast [TITLE] podajemy jakiś napis. 13. Klasa Author. a. Stwórz dokument Author (w \src\appbundle\document) z polami id i name (identycznie jak Book), getterami i seterami b. Stwórz formularz AuthorType (analogicznie do BookType) w \src\appbundle\form c. Stwórz kontroler AuthorController analogicznie jak kontroler BookController w \src\appbundle\controller d. Przetestuj kontroler AuthorController powinno działać: dodawanie, edycja, listing, usuwanie, wyszukiwanie autora po nazwie e. Dodaj kilku autorów 14. Połącz książkę z autorem relacją a. Dodaj odpowiednie klauzule use: use Doctrine\Common\Collections\ArrayCollection; b. Do dokumentu Author dodaj pole: * @var Book[] ArrayCollection * @ODM\ReferenceMany(targetDocument="Book", mappedby="author") protected $books; Oraz getter i setter do nowego pola. PhpStorm potrafi wygenerować takie metody z menu ALT+Insert c. Do dokumentu Author dodaj konstruktor: public function construct() $this->books = new \Doctrine\Common\Collections\ArrayCollection(); d. Do dokumentu Book dodaj pole:
* @var Author * @ODM\ReferenceOne(targetDocument="Author", inversedby="books")) protected $author; Dodaj getter i setter do nowego pola. Taki zabieg pozwoli śledzić relację w oba kierunki: książka wie, kto jest jej autorem, a autor wie, jakie napisał książki. e. Edytuj formularza BookType zmieniając metodę buildform na: public function buildform(formbuilderinterface $builder, array $options) $builder ->add('title') ->add('author', DocumentType::class, array( 'class' => 'AppBundle\Document\Author', 'multiple' => false )) ; f. Przetestuj metodę create kontrolera Book po wprowadzonych zmianach wysyłając żądanie typu POST do [ADRES]/app_dev.php/book/create z zawartością typu raw (JSON) o treści: "title" : "Tytul", "author" : "[ID_AUTORA]" Zamiast [ID_AUTORA] podaj ID wybranego dokumentu z kolekcji Author (możesz je sprawdzić za pomocą Robomongo) g. W ten sam sposób przetestuj akcję update ĆWICZENIE: 1. Dokument zwracany przez akcję z kontrolera domyślnie jest kompletnym dokumentem MongoDB uwzględnia wszystkie referencje do innych dokumentów. To co jest zwracane można kontrolować poprzez adnotację Groups. Użytkownik zobaczy wtedy tylko pola należące do danej grupy a. Dodaj do nagłówków dokumentów Book i Author dyrektywę use: use JMS\Serializer\Annotation\Groups; b. Do każdego pola w dokumencie dodaj adnotację @Groups("[nazwa_grupy]") [nazwa_grupy] zamień na dowolną nazwę. c. Zmień deklarację adnotacji View przy akcjach kontrolera, tak by wyświetlała tylko pola należące do danej grupy lub grup:
* @View(serializerGroups="book") Np. // BookControler.php * @Get("/", name="book_index") * @View(serializerGroups="book") public function indexaction(request $request) // code // Book.php * @var string * @Groups("book") * @ODM\Field(type="string") protected $title; W ramach ćwiczenia, popraw klasy dokumentów i kontrolerów, aby Wyświetlenie pojedynczej książki lub spisu książek nie wyświetlało wszystkich książek autora. Wyświetlenie pojedynczego autora wyświetliło wszystkie jego książki Wyświetlenie spisu autorów nie wyświetlało przypisanych do nich książek PODSUMOWANIE. Na zaliczenie będzie potrzebna następująca funkcjonalność: Dodawanie, edycja, usuwanie autora, podgląd autora o danym ID, wypisanie wszystkich książek, wyszukanie książki o cząstkowy tytule Dodawanie, edycja, usuwanie książki, podgląd książki o danym ID, wypisanie wszystkich autorów, wyszukanie autora o cząstkowej nazwie