Witaj Gościu! ( Zaloguj | Rejestruj )

Forum PHP.pl

 
Reply to this topicStart new topic
> [Laravel] Pobieranie rekordów zależne od roli
john_doe
post 25.01.2018, 10:27:54
Post #1





Grupa: Zarejestrowani
Postów: 873
Pomógł: 25
Dołączył: 24.07.2005

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


Hej

Każdy user jest przypisany do firmy.
User jest też przypisany do roli ( może mieć wiele ról ).
Chciałbym osiągnąć funkcjonalność gdzie:

NP 1 ) Admin widzi wszystko: dokumenty, wszystkie combosy wypełnione wszystkim, etc

NP 2 ) User widzi: dokumenty z jego firmy. Jeszcze nie wiem czy nagłówki dokumentów będę wiązał z userem czy z firmą. Ale dla tych dywagacji nie ma to większego znaczenia.
Będę też miał pozycje dokumentu. Trzeba coś wymyślić aby metoda showDocumentElements(int DocumentId) nie pozwalała zobaczyć pozycji z nieswojego dokumentu
Etc.
Proszę Was o podpowiedz, kawałek kodu, coś co zobrazuje jak to powinno być napisane.

Temat myśle bardzo uniwersalny i każdy z niego zaczerpie.

Nie chciałbym tworzyć osobnych kontrolerów dla ról.
Zastanawiam się czy nie wystawić serwisu jakiegoś, którego metody dostawałyby role usera i na ten podstawie pobierały z repozytorium odpowienie dane? ( na ifach )
Go to the top of the page
+Quote Post
r4xz
post 25.01.2018, 10:48:44
Post #2





Grupa: Zarejestrowani
Postów: 673
Pomógł: 106
Dołączył: 31.12.2008

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


Czy najprościej nie jest napisać proste Policy, które będzie dostawało id modelu albo sam model i na tej podstawie oceniało czy użytkownik ma do niego dostęp? Wydaje się to być jedno proste zapytanie sprawdzające czy dokument należy do użytkownika lub firmy do której należy (lub coś bardzo podobnego). Dla admina w metodzie before piszesz że ma dostęp do wszystkiego i sprawa rozwiązana.


--------------------
Go to the top of the page
+Quote Post
john_doe
post 25.01.2018, 11:06:46
Post #3





Grupa: Zarejestrowani
Postów: 873
Pomógł: 25
Dołączył: 24.07.2005

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


to mój 1szy Laravelowy projekt.
r4xz czy możesz zarzucić trochę kodem przykładowym?
Go to the top of the page
+Quote Post
r4xz
post 25.01.2018, 16:18:22
Post #4





Grupa: Zarejestrowani
Postów: 673
Pomógł: 106
Dołączył: 31.12.2008

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


Musisz zrobić sobie policy, możesz to zrobić poleceniem
Kod
php artisan make:policy DocumentPolicy
, a następnie w AuthServiceProvider musisz to jawnie wskazać który model ma z tego policy korzystać, znajdziesz to w sekcji "Registering Policies" (link w poprzednim moim poście). Potem w kontrolerze robisz tylko coś w stylu
Kod
if ($user->can('update', $document)) { /* ... */}
. Wszystko jest dokłądnie opisaane na tej jednej stronie którą podesłałem, przeczytaj, nie ma tego dużo.


--------------------
Go to the top of the page
+Quote Post
john_doe
post 25.01.2018, 22:07:34
Post #5





Grupa: Zarejestrowani
Postów: 873
Pomógł: 25
Dołączył: 24.07.2005

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


Tak czytałem to wszystko tylko nie rozumiem jak tego użyć w moim przypadku.
Policy kojarzą mi się z tym czy User może wykonać jakąś akcję czy nie.
Samo stworzenie tej klasy i jej rejestracja jest proste ale co w niej ma być?
Metoda before() tak jakby omijać miała wszystko to co jest zawarte poza nią.
Go to the top of the page
+Quote Post
phpion
post 26.01.2018, 07:10:11
Post #6





Grupa: Moderatorzy
Postów: 6 070
Pomógł: 860
Dołączył: 10.12.2003
Skąd: Dąbrowa Górnicza




Wtrącę z czystej ciekawości: rozumiem, że wspomniane zagadnienia dotyczą pojedynczego rekordu. Podczas edycji sprawdzane jest czy dany użytkownik może wprowadzić zmiany. A jak się to ma do listy rekordów? Bo żeby moc edytować rekord najpierw trzeba mieć go na liście rekordów i jak w tym momencie wyglada sprawa użycia policy?
Go to the top of the page
+Quote Post
john_doe
post 26.01.2018, 09:34:09
Post #7





Grupa: Zarejestrowani
Postów: 873
Pomógł: 25
Dołączył: 24.07.2005

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


dokładnie o to mi chodzi. Tak jak napisałem wcześniej, z lektury docsów Policy kojarzą mi się z prawami do rekordu. A sprawa dotyczy jak phpion zauwazył ( dzięki smile.gif ) listy.
Go to the top of the page
+Quote Post
r4xz
post 26.01.2018, 20:13:31
Post #8





Grupa: Zarejestrowani
Postów: 673
Pomógł: 106
Dołączył: 31.12.2008

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


Czyli tutaj:
Cytat
showDocumentElements(int DocumentId) nie pozwalała zobaczyć pozycji z nieswojego dokumentu

zamiast "zobaczyć pozycji z nieswojego dokumentu" powinno być raczej coś w stylu "zobaczyć tylko te pozycje w ramach dokumentu do których mamy dostęp". Zrozumiałem że chcesz to documentId weryfikować, jeśli chodzi o pobieranie z bazy tylko tych rekordów do których masz dostęp to sprawa się komplikuje i nie ma na to dobrego rozwiązania. Wiadomo, nie opłaca się pobrać wszystkich i na każdym wywoływać metody can więc jesteśmy zmuszeni zaszyć to w logice zapytania. Ja do tego celu używam query scopes. Jeśli chcesz mieć to w jednym miejscu to w modelu możesz sobie za pomocą DI doładować konkretne Policy, a w samym Policy tworzyć metody typu "editQuery" itp. - osobiście sam tak lubię robić, ponieważ wtedy uprawnieniami dla danego modelu steruję w jednej klasie. W modelu masz wtedy tylko np. scopeWhereUserCanEdit(...) { return $this->policy->editQuery(...); } lub scopeEditableBy(...) { ... } (kwestia nazewnictwa należy już do Ciebie).

--- edit ---

Swoją drogą jest to jeden z nie do końca przemyślanych use casów, które nadal nie są rozwiązane, a przynajmniej ich rozwiązanie nie jest sugerowane przez Laravel. A praktycznie problem ten występuje w każdym projekcie. Podobnie ma się sprawa z eloquent eager loading i sortowaniem wyników po kolumnie pochodzącej właśnie z ładowanej relacji. Moim zdaniem powinien być jakiś sprytny mechanizm w eloquent który pozwala na sterowanie czy obiekty pochodzące z relacji mają być wczytywane osobnym zapytaniem czy jako joiny. Oczywiście ten drugi wariant aktualnie trzeba robić samemu, a jego implementacja we frameworku pewnie byłaby uciążliwa dlatego wciąż jest to kwestia otwarta. No ale to taki mały offtop, Eloquent jest tutaj jednak pewnym słabym ogniwem w tym frameworku.

Ten post edytował r4xz 26.01.2018, 20:19:22


--------------------
Go to the top of the page
+Quote Post
john_doe
post 27.01.2018, 00:44:10
Post #9





Grupa: Zarejestrowani
Postów: 873
Pomógł: 25
Dołączył: 24.07.2005

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


R4xz dzieki. Myslalem, że czegoś nie rozumiem i Laravel ma coś out of the box więc wolałem spytać Was.

Napewno jednym z podejść jest query scopes
  1. public function scopeBelongingToUser($query)
  2. {
  3. return $query->where('user_id', auth()->user()->id);
  4. }
  5. public function scopeBelongingToAdmin($query)
  6. {
  7. if (auth()->user()->roles->contains('admin') {
  8. return $query->select('*');
  9. }
  10.  
  11. abort(403, 'Unauthorized');
  12. }
  13. public function documents()
  14. {
  15. $this->hasMany(Document::class);
  16. }
  17.  
  18. // i potem
  19. Document::belongingToUser();
  20.  
  21. Document::belongingToAdmin();


Lub coś takiego

  1. public function documents()
  2. {
  3. if ($this->hasRole('admin')) {
  4. return Document::all();
  5. } else {
  6. return $this->hasMany(Document::class);
  7. }
  8. }


Ten post edytował john_doe 27.01.2018, 00:47:44
Go to the top of the page
+Quote Post
r4xz
post 27.01.2018, 07:48:04
Post #10





Grupa: Zarejestrowani
Postów: 673
Pomógł: 106
Dołączył: 31.12.2008

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


Tego drugiego podejścia nie polecam, ponieważ wtedy użycie metody documents() zwraca Ci relacje albo wszystkie rekordy. Często pisze się takie struktury jak: $documents->elements()->where("price", ">", 100)->get(). U Ciebie to zadziała tylko w przypadku użytkownika, który nie jest adminem. Dodatkowo pobrać wszystkie rekordy możesz używając parametru ->documents (to hear czym innym niż metoda ->documents()). Efekt który chcesz można uzyskać wstawiając where zaraz za hasMany, ale wtedy Twój model posiada w sobie logikę biznesowa co moim zdaniem nie jest dobrym rozwiązaniem. Czasami możesz chcieć po prostu pobrać wszystkie elementy dokumentu niezależnie od tego na jakim jesteś koncie/użytkowniku.


--------------------
Go to the top of the page
+Quote Post
Pyton_000
post 27.01.2018, 09:39:54
Post #11





Grupa: Zarejestrowani
Postów: 8 068
Pomógł: 1414
Dołączył: 26.10.2005

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


Użyj czegoś na wzór Factory, czyli oddzielne repozytoria per user/admin a potem w fabryce robisz tylko instancję w zależności od upranienia.

Roziązań jest multum. smile.gif Kwestia wyobraźni. Ale ja bym raczej szedł właśnie w kierunku separacji logiki dla Admina i Usera w repozytoriach chyba.
Go to the top of the page
+Quote Post
john_doe
post 27.01.2018, 10:34:06
Post #12





Grupa: Zarejestrowani
Postów: 873
Pomógł: 25
Dołączył: 24.07.2005

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


Jak różne repozytoria? smile.gif
Repozytorium powinno byc jedno i co najwyzej w nim metody getAllDocs(), getDocsByUserId(), getDocsByCompanyId()
Dalej wystawić serwis np. z metodą getDocuments(Role role) i tutaj podejmować decyzje co zwrocic.
Masz racje ....opcji jest wiele
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 Wersja Lo-Fi Aktualny czas: 19.04.2024 - 22:04