Witaj Gościu! ( Zaloguj | Rejestruj )

Forum PHP.pl

> [SF][Symfony2][SF2] DAO, Abstrakcyjna warstwa dostępu do danych
Fluke
post
Post #1





Grupa: Zarejestrowani
Postów: 247
Pomógł: 9
Dołączył: 20.09.2010
Skąd: Kraków

Ostrzeżenie: (0%)
-----


Witam,

Mam pytanie odnośnie DAO (Data Access Object). Mam projekt, w którym obecnie korzystam z Doctrine ale może się to zmienić. W późniejszym czasie może zaistnieć sytuacja gdzie będę pobierał dane przez SOAP, json bądź csv. Chciałbym stworzyć warstwę abstrakcji dostępu do danych gdzie w kontrolerach nie będę musiał się zastanawiać czy korzystać z doctrine, json czy csv. W googlach znalazłem tylko to https://github.com/fightmaster/dao.

Jak wy radzicie sobie z tym problemem ?
Pozdrawiam.
Go to the top of the page
+Quote Post
 
Start new topic
Odpowiedzi (1 - 5)
Crozin
post
Post #2





Grupa: Zarejestrowani
Postów: 6 476
Pomógł: 1306
Dołączył: 6.08.2006
Skąd: Kraków

Ostrzeżenie: (0%)
-----


Niestety nie ma zbyt dobrze utartych standardów w tym zakresie, a większość FW/bibliotek/ogólnie kodu w sieci bardzo często utożsamia warstwę biznesową/modelu z ORM-em/bazą danych.
Przygotuj odpowiedni zestaw interfejsów, które w żaden sposób nie są powiązane ze źródłem danych, przykładowo:
  1. namespace My\Project\Model;
  2.  
  3. // obiekty domeny
  4. interface ArticleInterface {
  5. function getId();
  6. function getAuthor();
  7. function getTitle();
  8. }
  9.  
  10. interface UserInterface {
  11. function getId();
  12. function getUsername();
  13. }
  14.  
  15. // dao/repozytoria
  16. interface ArticleDao {
  17. function persist(ArticleInterface $article);
  18. function update(ArticleInterface $article);
  19. }
  20.  
  21. interface ArticleRepsitory {
  22. function find();
  23. function findOne($pk);
  24.  
  25. function findByAuthor(UserInterface $author);
  26. function findByCategory(CategoryInterface $category);
  27. function findByDateRage(DateTime $from, DateTime $to);
  28. }
  29.  
  30. // faktyczne usługi, z których mógłbyś korzystać wew. kontrolerów
  31. interface ArticleManager {
  32. function publish(ArticleInterface $article, UserInterface $publisher);
  33. function doSth(ArticleInterface $article);
  34. }
  35.  
  36. interface ArticlePromotionManager {
  37. function promoteArticle(ArticleInterface $article, DateInterval $duration);
  38. }
Konkretna implementacja jest już w pewnym sensie nieistotna.
Go to the top of the page
+Quote Post
billy0o
post
Post #3





Grupa: Zarejestrowani
Postów: 7
Pomógł: 1
Dołączył: 26.06.2009

Ostrzeżenie: (0%)
-----


W tym celu powinno używać się klas abstrakcyjnych z sufiksem Model:

  1. namespace Acme\DemoBunldle\Model;
  2.  
  3. abstract class UserModel
  4. {
  5. /**
  6.   * @return string imię
  7.   */
  8. abstract public function getName();
  9.  
  10. /**
  11.   * @param string $name imię
  12.   *
  13.   * @return User bieżąca instancja
  14.   */
  15. abstract public function setName($name);
  16.  
  17. /**
  18.   * @return string nazwisko
  19.   */
  20. abstract public function getLastName();
  21.  
  22. /**
  23.   * @param string $lastName nazwisko
  24.   *
  25.   * @return User bieżąca instancja
  26.   */
  27. abstract public function setLastName($lastName);
  28.  
  29. /**
  30.   * @return string imię i nazwisko
  31.   */
  32. public function getFullName() {
  33. return $this->getName() . " " . $this->getLastName();
  34. }
  35.  
  36. /**
  37.   * @param string $fullName imię i nazwisko
  38.   *
  39.   * @return User bieżąca instancja
  40.   */
  41. public function setFullName($fullName) {
  42.  
  43. if (!preg_match('#^[a-Z]+ [a-Z]+$#', $fullName)) {
  44. throw new \InvalidArgumentException();
  45. }
  46.  
  47. list($firstName, $lastname) = split(" ", $fullName, 1);
  48.  
  49. $this->setName($firstName);
  50. $this->setLastName($lastName);
  51.  
  52. return $this;
  53. }
  54. }


Implementacja:

  1. namespace Acme\DemoBundle\Entity;
  2.  
  3. use Acme\DemoBunldle\Model\UserModel;
  4.  
  5. class User extends UserModel
  6. {
  7. // wygenerowane przez Doctrine
  8. }


W kontrolerach oraz serwisach oczywiście wymagamy klasy UserModel i nie obchodzi nas skąd gettery biorą dane smile.gif

Należy pamiętać, że możemy rozszerzać tylko jedna klasę abstrakcyjną podczas gdy interfejsów można implementować wiele do jednej klasy.

Ten post edytował billy0o 23.10.2014, 22:41:35
Go to the top of the page
+Quote Post
Fluke
post
Post #4





Grupa: Zarejestrowani
Postów: 247
Pomógł: 9
Dołączył: 20.09.2010
Skąd: Kraków

Ostrzeżenie: (0%)
-----


Dzięki wielkie za odpowiedź.

Myślałem, żeby zrobić serwis, który by mi zwracał odpowiedni serwis np UserManager, ArticleManager. W pliku konfiguracyjnym bym mógł ustawić z czego korzystam (doctrine, csv, yml, soap, itp). W kontrolerze mógłbym wywoływać serwis:

  1. /** @var UserManager */
  2. $userManager = $this->get('dao.manager')->get('user');
  3. $userManager->find($id);


W metodzie get klasy DaoManager jako 2 parametr moglibyśmy ustawiać z jakiego źródła pobierać. Jeśli nie został przekazany to default`owo źródło jest takie jak ustawiliśmy w pliku konfiguracyjnym.

Czy brzmi to w miarę logicznie ?
Pozdrawiam.
Go to the top of the page
+Quote Post
billy0o
post
Post #5





Grupa: Zarejestrowani
Postów: 7
Pomógł: 1
Dołączył: 26.06.2009

Ostrzeżenie: (0%)
-----


Brzmi logicznie ale wydaje mi się, że jest to o jeden serwis za dużo. Możesz po prostu zmieniać klasę serwisu poprzez parametr:

Kod
parameters:
   acme.user_menager.class: Acme\ExampleBundle\Doctrine\UserMenager

services:
   acme.user_menager:
       class: %acme.user_menager.class%
       arguments: [@service_container]


Parametr acme.user_menager.class możesz zmienić w pliku parameters.yml, bądź w klasie Extension parsując config. DI w sf2 pozwala uniknąć właśnie takich konfiguracyjnych obiektów i po to został stworzony.
Go to the top of the page
+Quote Post
kpt_lucek
post
Post #6





Grupa: Zarejestrowani
Postów: 428
Pomógł: 77
Dołączył: 10.07.2011
Skąd: Warszawa

Ostrzeżenie: (0%)
-----


A ja bym to zrobił nieco inaczej...

Wątpię abyś chciał modyfikować wywołania swoich metod w każdym miejscu gdzie już istnieją... Pomyślałbym o zastosowaniu adapterów opartych o jeden interface. Przy takim podejściu logika wywołująca metodę getUser() zawsze zwróci usera, nie zależnie który adapter został wybrany. Jak dla mnie to najprostrze i zarazem optymalne gdyż jeżeli zmiana w strukturze danych nastąpi, to modyfikujesz jedno miejsce - dany adapter.

Robiłem coś podobnego przy okazji pisania pobierania informacji o użytkowniku logującym się przez Facebook/Linkedin/Google+ etc. Nie zależnie który serwis, zawsze używasz tej samej metody, oczywiście co się dzieje po drodze to już Twoja sprawa.


Pozdrawiam


--------------------


Cytat
There is a Bundle for that
Lukas Kahwe Smith - October 31th, 2014
Go to the top of the page
+Quote Post

Reply to this topicStart new topic
1 Użytkowników czyta ten temat (1 Gości i 0 Anonimowych użytkowników)
0 Zarejestrowanych:

 



RSS Aktualny czas: 21.08.2025 - 15:45