Pomoc - Szukaj - Użytkownicy - Kalendarz
Pełna wersja: [PHP][SQL]moduł osiągnięcia na 30dni
Forum PHP.pl > Forum > Przedszkole
phpuser88
Załóżmy, że chce wyświetlić użytkownikowi możliwość zdobywania osiągnięć, a każde osiągnięcie ma swój własny postęp i zostanie zrealizowane gdy osiągnie swój max.postęp - o ile max.postęp zostanie osiągnięty w max.30dni od chwili zrealizowania pierwszego postępu.
Przykład:
1. Tytuł osiągnięcia: Aktywny komentator
2. Opis osiągnięcia: podejmij się napisania 15x różnorodnych komentarzy powyżej 100 znaków w ciągu 30 dni.
3. Postęp: 0 / 15

Stworzyłem sobie funkcje, która wyświetla właściwy html, ale mam zagwozdkę jak rozsądnie stworzyć bazę danych, bo każde osiągnięcie można zrealizować wciągu 30 dni od chwili zrealizowania pierwszego "postępu", a to wyklucza proste i optymalne rozwiązanie jakim jest wrzucenie wszystkiego w jedną tabele pod ID_USERA i jedynie updatowanie poszczególnych osiągnięć +1 w danym wierszu. Tutaj raczej trzeba dodać jeszcze date realizacji i ew. crona do czyszczenia, a to generalnie zrobi wielki ruch w tabeli, bo z np. 1000000 wpisów zrobi się 1000000*ilość osiągnięć*max.postęp.
Nie jestem zbyt zaawansowany więc niestety nie znam wielu fajnych rozwiązań więc zanim zrobię to tak, jak to widzę w powyższym okropnym opisie wolę zapytać czy istnieje lepszy pomysł?
Tak to widzę:
  1. #BazaSQL:
  2. id_usera | dataRealizacji | osiagniecie1 | osiagniecie2 | osiagniecie3 |
  3. 123456 | 21.01.22 | 0 | 0 | 1 |
  4. 123456 | 21.04.22 | 0 | 0 | 1 |
  5. 123456 | 28.04.22 | 0 | 0 | 1 |
  6. 123456 | 01.05.22 | 0 | 0 | 1 | //to jest ID_usera, który ma postęp 3x w Osiągnięciu3
  7.  
  8. #PHP
  9. function osiagniecia($tytul,$postep,$postepMax,$opis){...}
  10.  
  11. echo osiagniecia("tytul osiagniecia",$row['osiagniecie3 '],15,"opis osiagniecia do zrealizowania");
trueblue
A jeśli nie osiągnie postępu, to może przystąpić do osiągnięcia jeszcze raz?
phpuser88
może przystąpić jeszcze raz, ważne aby osiągnął komplet w 30 dni - jeżeli nie osiągnie kompletu, to kolejno każdy postęp osiągnięcia będzie wygasać po 30 dniach.

edit:
Teraz wpadłem na trochę inny pomysł,a mianowicie stworze 30 kolumn odpowiadające za każdy dzień z trzydziestu i jeśli jakieś osiągnięcie zostanie zrealizowane danego dnia, to przypisze mu unikalny identyfikator z sumą i wpakuje do bazy, a później jakoś w PHP to poskładam w całość:
Coś tego typu:
  1. #BazaSQL:
  2. id_usera | dzien1 | dzien2 | dzien3 | dzienX |
  3. 123456 | #id:2=1 | 0 | 0 | 0 |
  4. 123456 | 0 | #id:2=1#id:4=1 | 0 | 0 |
  5. 123456 | 0 | 0 | 0 | #id:2=1 |

Ale to nadal tylko gdybanie nad sensownym rozwiązaniem.

edit2:
To rozwiązanie jest niewypałem... bo jeśli user zrealizuje pierwsze osiągnięcie 30 dnia, to powinien mieć czas 30 dni na realizacje całego postępu, a tu w teorii wszystko powinno być kasowane dry.gif
Czyli całość musi być oparta na datach i wychodzi na to, że pierwsze założenie jest niestety prawidłowe. sciana.gif

edit3:
Chyba że dodam kolejną kolumnę z nazwą osiągnięcia i pierwszy postęp to będzie `dzien1`.
Następnie z wszystkich kolumn stworze tzw. licznik aby wiedzieć na którym dniu jest aktualnie dane osiągnięcie. Mogę to chyba zrobić za pomocą crona dodając każdego dnia +1 do `dzien2` (tj. nastepnego dnia gdzie dzienX==0) - w sensie jeśli dzień >0 i następny dzień==0, to jest to ten dzień na którym stoi całe osiągnięcie. Później w PHP odejmę 1 od każdego dnia i uzyskam prawidłową sume postępu danego osiągnięcia...
Dzięki temu zredukuje tone wpisów i liczenia o ile myślę w prawidłowy sposób haha co_jest.gif
  1. #BazaSQL:
  2. id_usera | osiagniecie | dzien1 | dzien2 | dzien3 | dzienX |
  3. 123456 | 10 | 2 | 2 | 2 | 0 | //=3
  4. 123456 | 50 | 2 | 1 | 2 | 0 | //=2

Tu jest chyba taki minus, że każdy postęp osiągnięcia NIE będzie wygasać po 30 dniach, a zamiast tego wygaśnie całe osiągnięcie wraz z wszystkimi postępami, ale to raczej lepsze rozwiązanie od pierwszej metody.
trueblue
Czy to oznacza, że mogę dokonać jednego postępu na dzień?
phpuser88
Nie, można dokonać nawet wszystkich postępów jednego dnia.
trueblue
Jak będziesz identyfikował konkretny postęp? Czy każdy postęp jest innym działaniem?
phpuser88
Każdy postęp jest innym działaniem. Myślę, że za pomocą unikalnego ID. Jeszcze dokładnie tego nie przemyślałem, ale tak to widzę.
Przykładowo jeśli chodzi o przykład:
Cytat
Przykład:
1. Tytuł osiągnięcia: Aktywny komentator
2. Opis osiągnięcia: podejmij się napisania 15x różnorodnych komentarzy powyżej 100 znaków w ciągu 30 dni.
3. Postęp: 0 / 15

To myślę aby każdy komentarz przed insertem w komentarze sprawdzić dodatkowo pod kątem ilości znaków i jeśli znaki>99, to +1 do postępu z ID(osiagniecia_komentarze)

edit: ha!... czyli jeśli zastosuje rozwiązanie z edit3 będę musiał za każdym razem weryfikować w jaki dzień dodać update+1 - troche kulawo...
trueblue
Tabela:
id_user, numer_osiagniecia, data_start, data_ostatni_postep, id_ostatni_postep
Wpisujesz start danego osiągnięcia (nie wiem kiedy u Ciebie przypada ten termin - po zrealizowaniu pierwszego postępu?).
Kiedy użytkownik zrealizuje dany postęp, wpisujesz (aktualizujesz) jego date i id w tabeli.
id_ostatni_postep informuje czy użytkownik osiągnał całość. Możesz też dodać odrębne pole na wartość postępu.

To jest najprostsze rozwiązanie, ale niekoniecznie najlepsze.

Innym było po prostu zapisywanie kolejnych postępów:

user_osiagniecie:
id_user_numer_osiagniecia, id_user, numer_osiagniecia, data_start
osiagniecie_postep:
id_user_numer_osiagniecia, data_postep, id_postep

lub na jednej tabeli, jeśli data startu osiągnięcia jest równoznaczna z zakończeniem pierwszego postępu:
id_user, numer_osiagniecia, data_postep, id_postep


Wszystko zależy od specyfiki Twojego problemu.

phpuser88
Tak, data_start to realizacja pierwszego postępu, ale w sumie to chyba jej nie potrzebuje. dry.gif
Myślę aby weryfikację całości zostawić całkiem po stronie PHP, a w bazie trzymać jedynie tzw. licznik.
Na podstawie Twoich przykładów zlepiłem coś takiego w jedną tabele:
(przy założeniu, że data_koniec oznacza koniec czasu na realizację danego osiągnięcia)

id_user, id_osiagniecia, postep_osiagniecia, data_koniec(+30dni)

Czyli jeśli chcemy dodać nowy postęp, to musimy najpierw sprawdzić czy istnieje oraz if(data_koniec>$data_dzis), a następnie updatować+1, a jeśli data końca przeminęła zrobić update daty_konca i postep=1 (jako rozpoczęcie od nowa osiągnięcia). Albo za pomocą crona sprawdzać i czyścić raz dziennie przestarzałe daty.

A funkcje wyświetlania ustawić jakoś tak:
function osiągnięcia($id,$postepSQL,$postepMax,$data_koniecSQL,$tytul,$opis);

Hmm... patrząc na Twoje wzorce wydaje się to całkiem proste... a ja sobie od początku ostro komplikowałem facepalmxd.gif dzięki wielkie za naprowadzenie! biggrin.gif
trueblue
Cron tu raczej nie jest potrzebny.
Przyda się jednak data_start i data_ostatni_postep.
Dzięki data_start, wiesz czy działania mieszczą się w 30 dniach. Aktualizacja postępu może nastąpić jeśli aktualna_data-data_start<=30 dni.
Tak więc użytkownik poprzez swoje działania, a następnie Twój skrypt, zaktualizuje datę ostatniego postępu i sam postęp.

Chyba, że piszesz o sytuacji kiedy użytkownik nie zrealizował osiągnięcia i chcemy dodać nowe. Wtedy można to zrobić cronem lub też przed zapisem nowego, pierwszego postępu danego osiągnięcia.
phpuser88
Hmm myślałem bardziej w sposób, że jeśli użytkownik doda +1 do postępu osiągnięcia, to automatycznie `data_koniec` przyjmuje wartość +30dni na spełnienie całości osiągnięcia.
Jeśli ma nastąpić kolejny update_postep+1, to sprawdzamy czy $data_dziś<`data_koniec` - to raczej powinno wystarczyć. Nieco ograniczy możliwości użytkownika przy realizacji osiągnięcia, bo zostanie mu odebrany postęp dodany np. 29 dnia, jeśli niefortunnie data_konca tak zakłada. Z drugiej strony teraz myślę, że jeśli użytkownik zrealizuje cały postęp w osiągnięciu, to powinno być ono ważne przez następne 30dni więc `data_start` mogłaby odpowiadać właśnie za czas działania korzyści ze zrealizowanego osiągnięcia. Tak to widzę i chyba już całkiem poprawnie dzięki Tobie. biggrin.gif
trueblue
Czy dobrze rozumiem, że użytkownik ma 30 dni na wypełnienie postępu od ostatniego działania (czyli de facto na każdy postęp), a nie 30 dni na całość osiągnięcia?
phpuser88
No ostatecznie tak, bo dzięki temu zamknę się z jednym osiągnięciem w jednym wierszu. User ma 30 dni na zrobienie wszystkich postępów od chwili zrealizowania pierwszego postępu w danym osiągnięciu. Nie jest to eleganckie w stosunku do usera, ale wydajność jest istotniejsza. Coś pomieszałem w tym założeniu? haha

Przy założeniu że chodzi o osiągnięcie z przykładu:
1. Tytuł osiągnięcia: Aktywny komentator
2. Opis osiągnięcia: podejmij się napisania 15x różnorodnych komentarzy powyżej 100 znaków w ciągu 30 dni.
3. Postęp: 0 / 15

Zrobiłbym to tak, aby dodać +1:
  1. if($INSERT_KOMENTARZ){//dodano nowy komentarz
  2. if(strlen($tresc_komentarza)>99){//sprawdz czy komentarz kwalifikuje sie na osiagniecie
  3. $datakoniec = date("Y-m-d", strtotime('+30 day'));
  4. $datadzis = date("Y-m-d");
  5. $sql="SELECT * FROM `osiagniecia` WHERE `user`='123456' AND `idos`=1 LIMIT 1";
  6. if($result = mysqli_query($con, $sql)){
  7. if(mysqli_num_rows($result)){//sprawdz czy istnieje
  8. while($row = mysqli_fetch_assoc($result)){
  9. if($row['koniec']>$datadzis){
  10. UPDATE `osiganiecia` SET `postep` = postep+1 WHERE `user` = 123456 AND `idos`=1; //dodaj +1 skoro user ma jeszcze czas na realizacje
  11. }else{//istnieje, ale czas zostal przekroczony
  12. UPDATE `osiganiecia` SET `postep` = 1, `koniec` = '$datakoniec' WHERE `user` = 123456 AND `idos`=1; //ustawia od nowa postep=1 i date_konca+30dni
  13. }
  14. }
  15. }else{//nie istnieje
  16. INSERT INTO `osiganiecia` (`id`, `user`, `idos`, `postep`, `koniec`, `start`) VALUES (NULL, '123456', '1', '1', '$datakoniec', '0000-00-00'); //dodaj osiagniecie z postepem i max.data jako rama czasowa
  17. }}}}
To jest wersja lo-fi głównej zawartości. Aby zobaczyć pełną wersję z większą zawartością, obrazkami i formatowaniem proszę kliknij tutaj.
Invision Power Board © 2001-2025 Invision Power Services, Inc.