Witaj Gościu! ( Zaloguj | Rejestruj )

Forum PHP.pl

 
Reply to this topicStart new topic
> [SF][SF2][Symfony2] Co tu jest nie tak ?, jak zoptymalizować ten kawałek kodu ?
damianooo
post
Post #1





Grupa: Zarejestrowani
Postów: 496
Pomógł: 2
Dołączył: 15.07.2011
Skąd: Katowice

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


Chciałem się zapytać czy dobrze rozwiązałem poniższy problem:

Mam takie encje:

  1. users {id}
  2. matchdays {id}
  3. matches {id,matchday_id}
  4. points {id,user_id,match_id,numberOfpoints}


Potrzebuję pobrać dane tak aby wyświetlić dla każdego użytkownika sumy punktów dla każdej osobnej kolejki plus na końcu sumę wszystkich punktów ze wszystkich kolejek , tak aby później wyświetlić to w widoku TWIG, coś w tym stylu:

Imie /k1 /k2 /k3 /k4 /k5 / suma
---------------------------------
User3 / 4 / 2 / 4 / 2 / 4 / 16
User1 / 2 / 0 / 4 / 4 / 2 / 12
User2 / 2 / 0 / 2 / 4 / 2 / 1

Zrobiłem to tak:

  1. namespace My\TyperkaBundle\Repository;
  2. use Doctrine\ORM\EntityRepository;
  3.  
  4. class TypeRepository extends EntityRepository {
  5.  
  6. private $sum_per_user = array();
  7. private $users = array();
  8. private $final_result = array();
  9.  
  10. public function getPointsPerMatchday(){
  11.  
  12. $qb = $this->createQueryBuilder('t');
  13. $qb->select(
  14. 'SUM(t.numberOfPoints) AS suma'
  15. ,'u.username AS username'
  16. ,'u.id AS user'
  17. ,'u.priority'
  18. ,'md.id as matchday'
  19. )
  20. ->innerJoin('t.match', 'm')
  21. ->innerJoin('m.matchday', 'md')
  22. ->innerJoin('t.user', 'u')
  23. ->where('md.id BETWEEN 1 AND 15')
  24. ->groupBy('u.username, md.id')
  25. ;
  26.  
  27. $result = $qb->getQuery()->getResult();
  28.  
  29. // 1. Pobranie tylko użytkowników
  30. foreach ($result as $details){
  31. $this->users[] = $details['user'];
  32. }
  33.  
  34. // 2. Wybranie unikalnych wartości
  35. $this->users = array_unique($this->users);
  36.  
  37. // 3. Uporządkowanie kluczy
  38. $keys = array(0,1,2,3,4,5,6,7,8,9);
  39. $this->users = array_combine($keys, $this->users);
  40.  
  41. // 4. Zsumowanie punktów dla każdego użytkownika
  42. for($i=0;$i<10;$i++){
  43. foreach ($result as $details){
  44. if($this->users[$i] == $details['user']){
  45. if(!isset($this->sum_per_user[$this->users[$i]])){
  46. $this->sum_per_user[$this->users[$i]] = 0;
  47. }
  48. $this->sum_per_user[$this->users[$i]] = $this->sum_per_user[$this->users[$i]] + (int)$details['suma'];
  49. }
  50. }
  51. }
  52.  
  53. // 5. Posortowanie użytkowników wg sumy punktów
  54. arsort($this->sum_per_user);
  55.  
  56. // 6. Kolejne uporządkowanie kluczy
  57. $this->users = array_combine($keys, array_keys($this->sum_per_user));
  58.  
  59. // 7. Uporządkowanie danych użytkowników wg sumy punktów ze wszystkich kolejek
  60. // oraz zmiana wyglądu tablicy na: dla każdego użytkownika sumy punktów w każdej kolejce
  61. foreach($this->users as $user){
  62. foreach ($result as $details){
  63. if($user == $details['user']){
  64. if(isset($user)){
  65. $this->final_result[$details['username']][] = (int)$details['suma'];
  66. }
  67. }
  68. }
  69. }
  70.  
  71. return $this->final_result;
  72. }



Proszę o uwagi. Co zrobiłem źle ? Jak można to inaczej (może prościej) napisać ?
Będę wdzięczny za poprawki do kodu.

Go to the top of the page
+Quote Post
nospor
post
Post #2





Grupa: Moderatorzy
Postów: 36 557
Pomógł: 6315
Dołączył: 27.12.2004




Cytat
Co zrobiłem źle ?
W jakim sensie zrobiles zle? Dane ci wyswietlaja nie tak jak chcesz czy moze poprostu pytasz czy mozna to zrobic optymalniej?
Go to the top of the page
+Quote Post
damianooo
post
Post #3





Grupa: Zarejestrowani
Postów: 496
Pomógł: 2
Dołączył: 15.07.2011
Skąd: Katowice

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


Dane wyświetlają się tak jak powinny a więc tutaj jestem zadowolony.

Pytam właśnie czy można to zrobić lepiej/porządniej/profesjonalniej w Symfony ?
Nie wiem po prostu czy nie napsiałem za dużo kodu, czy pokazując taki kod komuś nie powinienem się wstydzić (IMG:style_emoticons/default/wink.gif)
Go to the top of the page
+Quote Post
nospor
post
Post #4





Grupa: Moderatorzy
Postów: 36 557
Pomógł: 6315
Dołączył: 27.12.2004




z punktami 1 2 3 faktycznie troche przekombinowales...Wszystko to da sie zrobic tak:
  1. foreach ($result as $details){
  2. $this->users[$details['user']] = $details['user'];
  3. }

i juz. Masz zalatwione duplikaty tez tym sposobem. Dodaj tylko sortowanie do select po userid i po sprawie.

Nie nadawaj aliasu na ID jako user.... to jest user_id a nie user. to dwie rozne rzeczy.
Czemu zakladasz ze mozesz miec max 10 userow - kolejna rzecz do poprawki. Pisze petle uniwersalne.

Poza tym punnkty 1 2 3 4 mozna zrobic w jednej petli zamiast 1000 razy latac po tej samej petli w roznych czesciach kodu. Tu masz grupowanie:
http://nospor.pl/grupowanie-wynikow.html
Nie jest to co ty tu masz, ale rozniez uzywa grupowania w jednym obiegu petli zamiast w kilku.

Dalszych punktow nie sprawdzalem, bo troche mam wlasnej roboty
Go to the top of the page
+Quote Post
damianooo
post
Post #5





Grupa: Zarejestrowani
Postów: 496
Pomógł: 2
Dołączył: 15.07.2011
Skąd: Katowice

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


trochę mnie natchnąłeś ... i udało się fajnie zoptymalizować:

Podsumujmy:

// z SQLa miałem taką tablicę:
  1. $result = array(
  2. 0 => array("suma" => "26","username" => "Adam 1","user" => 9,"priority" => 1,"matchday" => 1),
  3. 1 => array("suma" => "23","username" => "Adam 1","user" => 9,"priority" => 1,"matchday" => 2),
  4. 2 => array("suma" => "20","username" => "Adam 1","user" => 9,"priority" => 1,"matchday" => 3),
  5. 3 => array("suma" => "18","username" => "Adam 1","user" => 9,"priority" => 1,"matchday" => 4),
  6. 4 => array("suma" => "14","username" => "Damian","user" => 12,"priority" => 2,"matchday" => 1),
  7. 5 => array("suma" => "22","username" => "Damian","user" => 12,"priority" => 2,"matchday" => 2),
  8. itd ...
  9. );


// 1. Sumuję więc łącznie wszystkie punkty ze wszystkich kolejek dla każdego usera
  1. foreach($result as $details){
  2. if(!isset($this->users[$details['user']])){
  3. $this->users[$details['user']] =0;
  4. }
  5. $this->users[$details['user']] = $this->users[$details['user']] + (int)$details['suma'];
  6. }


// otrzymuję to:
  1. $users = array(
  2. 9 => 87,
  3. 12 => 86,
  4. 2 => 90,
  5. 3 => 88,
  6. itd...
  7. );


// 2. Sortuję aby wiedzieć kto ma najwięcej punktów
  1. arsort($this->users);


// otrzymuję to:
  1. $users = array(
  2. 5 => 104,
  3. 16 => 102,
  4. 18 => 94,
  5. 13 => 92,
  6. 2 => 90,
  7. itd...
  8. );


// 3. Przypisuję punkty dla każdej kolejki osobno dla posortowanych już userów
// według łącznej sumy wszystkich punktów ze wszystkich kolejek
  1. foreach($this->users as $key => $value){
  2. foreach ($result as $details){
  3. if($key == $details['user']){
  4. $this->final_result[$details['username']][] = (int)$details['suma'];
  5. }
  6. }
  7. }


// i otrzymuję to co chcę a więc to:
  1. $final_result = array(
  2. "Mateusz" => array(24,26,28,26),
  3. "Tomek" => array(26,24,26,26),
  4. "Wojtek" => array(28,22,22,22),
  5. itd ...
  6. );



można to jeszcze zoptymalizować albo zrobić lepiej ?

Ten post edytował damianooo 26.01.2016, 20:54:20
Go to the top of the page
+Quote Post
nospor
post
Post #6





Grupa: Moderatorzy
Postów: 36 557
Pomógł: 6315
Dołączył: 27.12.2004




nie: $this->users[$details['user']] = $this->users[$details['user']] + (int)$details['suma'];
a: $this->users[$details['user']] += (int)$details['suma'];

prosilem bys uzywal user_id... oj, bo sie pogniewamy...


$this->final_result[$details['username']][] = (int)$details['suma'];
kluczem powinno byc id usera nie jego name. userzy teoretycznie moga miec te same name, id nie
Go to the top of the page
+Quote Post
damianooo
post
Post #7





Grupa: Zarejestrowani
Postów: 496
Pomógł: 2
Dołączył: 15.07.2011
Skąd: Katowice

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


ok poprawiłem i mam teraz tak:

  1. // 1. Sumuję łącznie wszystkie punkty ze wszystkich kolejek dla każdego usera
  2. foreach($result as $details){
  3. if(!isset($this->users[$details['user_id']])){
  4. $this->users[$details['user_id']] =0;
  5. }
  6. $this->users[$details['user_id']] += (int)$details['suma'];
  7. }
  8.  
  9. // 2. Sortuję aby wiedzieć kto ma najwięcej punktów
  10. arsort($this->users);
  11.  
  12. // 3. Przypisuję punkty dla każdej kolejki osobno dla posortowanych już userów
  13. // według łącznej sumy wszystkich punktów ze wszystkich kolejek
  14. foreach($this->users as $key => $value){
  15. foreach ($result as $details){
  16. if($key == $details['user_id']){
  17. $this->final_result[$details['username']][] = (int)$details['suma'];
  18. }
  19. }
  20. }


Apropo tego, że kluczem powinno być id a nie nazwa usera to wiem (IMG:style_emoticons/default/smile.gif) ... ja to zrobiłem tak celowo ponieważ potrzebuję takiej właśnie tablicy aby ją wyrzucić w TWIGu ... id mi tam nie są potrzebne , to ma być wyświetlone tak:

Imie /k1 /k2 /k3 /k4 /k5 / suma
---------------------------------
User3 / 4 / 2 / 4 / 2 / 4 / 16
User1 / 2 / 0 / 4 / 4 / 2 / 12
User2 / 2 / 0 / 2 / 4 / 2 / 10

Rozumiem, że imiona mogą się powtarzać ale ja mam to w mojej aplikacji rozwiązane tak że jak jest np. dwóch Marków to jeden jest Marek 1 a drugi Marek 2

Ten post edytował damianooo 27.01.2016, 09:56:19
Go to the top of the page
+Quote Post
nospor
post
Post #8





Grupa: Moderatorzy
Postów: 36 557
Pomógł: 6315
Dołączył: 27.12.2004




Nabrales zlych nawykow i zamiast je zmienic, poki masz okazje, to twardo przy nich trwasz.... Kiedys sie na tym przejedziesz, ale to juz twoja sprawa
Go to the top of the page
+Quote Post
damianooo
post
Post #9





Grupa: Zarejestrowani
Postów: 496
Pomógł: 2
Dołączył: 15.07.2011
Skąd: Katowice

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


... wolę zmienić nawyki ...

Obecnie w TWIGu miałem tak:

  1. {% for key,point in points %}
  2. {{ key }}
  3. {% for pt in point %}
  4. {{ pt }}
  5. {% set sum = sum + pt %}
  6. {% endfor %}
  7. {{ sum }}
  8. {% endfor %}


jak zmienię poniższy kawałek kodu z:

  1. $this->final_result[$details['username']][] = (int)$details['suma'];


na

  1. $this->final_result[$details['user_id']][] = (int)$details['suma'];


to w TWIGu będę miał IDki a tego nie chcę ...

jak to powinno wyglądać ?
Go to the top of the page
+Quote Post
nospor
post
Post #10





Grupa: Moderatorzy
Postów: 36 557
Pomógł: 6315
Dołączył: 27.12.2004




tablica final_result powinna wygladac tak:
2 => [
'name' => 'mateusz',
'sums' => [24,26,28,26]
],
4 => .....

Masz wowczas uniwersalna tablice, niezalezna od ewentualnych takich samych nazw a gdy najdzie potrzeba mozesz do niej dodawac kolejne elementy dla kazdego usera bez przerabiania polowy kodu.
Go to the top of the page
+Quote Post
damianooo
post
Post #11





Grupa: Zarejestrowani
Postów: 496
Pomógł: 2
Dołączył: 15.07.2011
Skąd: Katowice

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


a więc powinno to być tak zrobione:

  1. foreach($this->users as $key => $value){
  2. foreach ($result as $details){
  3. if($key == $details['user_id']){
  4. $this->final_result[$details['user_id']]['username'] = $details['username'];
  5. $this->final_result[$details['user_id']]['suma'][] = (int)$details['suma'];
  6. }
  7. }
  8. }


w związku z tym TWIG powinien być taki:

  1. {% for key,point in points %}
  2. {{ point.username }}
  3. {% for pt in point.suma %}
  4. {{ pt.suma }}
  5. {% set sum = sum + pt.suma %}
  6. {% endfor %}
  7. {{ sum }}
  8. {% endfor %}


pięknie (IMG:style_emoticons/default/smile.gif)

dzięki nospor pozdrawiam


Go to the top of the page
+Quote Post
lukaskolista
post
Post #12





Grupa: Zarejestrowani
Postów: 872
Pomógł: 94
Dołączył: 31.03.2010

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


Czy czasem repozytoria obiektów nie powinny zwracać właśnie obiektów, które obsługują lub ich kolekcji? Może lepiej przenieść generowanie tych statystyk na zewnątrz repozytorium, np. do jakiejś logiki, np.:
  1. namespace Costam/abc;
  2.  
  3. use Doctrine\Common\Collections\Collection;
  4.  
  5. interface CalcUserStats
  6. {
  7. public function calcCosTam(Collection $users);
  8. }

W tej sposób uniezależniasz się od źródła danych, bo równie dobrze tacy użytkownicy mogą pochodzić z cache lub jakiejś zewnętrznej usługi po REST/WS.
Go to the top of the page
+Quote Post

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

 



RSS Aktualny czas: 24.08.2025 - 21:58