Avatar billede PHPnQrd Nybegynder
24. november 2010 - 10:36 Der er 35 kommentarer og
1 løsning

PHP Interval - matematisk helvede

Kære Eksperter.
Mangler jeres hjælp!

Lad os antage Anders opretter en opgave i mit system.

Her skal den så sige:
o Brugere med rating over 4 får opgaven tilsendt med det samme.

o Brugere med en rating over 3 bliver synlige 30 minutter efter oprettelsestidspunktet af opgaven.

o Resten (Brugere under en rating på 3) - bliver synlig en time efter, hvis der stadig er opgaver, der ikke er fuldført.

o Hvis der er gået 4 timer, og der stadig er ledige tests (ingen som har accepteret opgaven), så udsendes en mail til alle testere.


Hvordan laver jeg dette rent praktisk med struktur? Jeg mener, jeg har et felt som hedder "oprettelsestidspunkt" i min db, hvor det er tidspunktet en opgave er blevet oprettet på.

Der skal være køre noget cronjob etc., men hvor tit, hvordan og hvorledes?

Er der en klog en der vil komme med kodeeksempler og et godt råd til at komme i gang?
Avatar billede PHPnQrd Nybegynder
24. november 2010 - 16:41 #1
Ville dette være en god løsning??


<?php
include("dbString.php");

/**
  *      Cronjob dette hvert 10 min.
  **/


// hent alle aktive opgaver

$e = mysql_query("SELECT * FROM test WHERE aktiv = 1");
while ( $row = mysql_fetch_assoc($e ) )
{

        //Tjek om opgaven er blevet oprettet for 30 min. siden
        if ( $row['tid'] >=( time()-1800)) {
        //Tjek om nogen har accepteret denne opgave endnu.

        $tjek = mysql_query("SELECT id FROM accepteret WHERE opgave_id = '".$row['id']."' AND accepteret = 1");
        if ( mysql_num_rows ( $tjek ) >= $row['antal_brugertest']) {
              // Ikke brug for flere testere.
        } else {
              //Der er brug for flere testere, derfor send til dem med rating på over 3.

                $HentBrugere = mysql_query("SELECT * FROM testere WHERE aktiv = 1");
                while  ($r = mysql_fetch_assoc($HentBrugere ) )
                {
                      $rating = mysql_query("SELECT AVG(rating) AS rating FROM rating WHERE tester = '".$r['id']."'");
                      $ratingn = mysql_fetch_assoc($rating);

                      if ( $ratingn == 3 ) {
                                  //Udsend til tester
                      }
                }
        }
        }


}
?>
Avatar billede repox Seniormester
25. november 2010 - 14:51 #2
Det mest praktiske ville egentlig være at give dine opgaver et status-felt også som eventuelt hænger sammen med rangen:

<?php

    // Nyoprettede opgaver oprettes med opgavestatus 4 og opgaven ikke er udført
    $sql = "SELECT * FROM opgaver WHERE opgavestatus != 0 AND aktiv = 1";
    $res = mysql_query($sql);
   
    while( $row = mysql_fetch_object($res) )
    {
        // En hurtig sætning til at opdatere den pågældende opgave, om nødvendigt.
        $sql = "UPDATE opgaver SET opgavestatus = opgavestatus - 1 WHERE opgaveId = ".$row->opgaveId;
       
        // Alderen på opgaven kan vi jo godt hente
        $age = time() - strtotime($row->oprettelsestidspunkt);
       
        if($row->opgavestatus == 4)
        {
            // send til alle med rang 4 eller derover       
        }
       
        if($row->opgavestatus == 3)
        {
            // Hvis ikke opgaven er 30 min (eller mere) gammel, skal databasen ikke opdateres og vi fortsætter (vha. 'continue') vores løkke med næste opgave
            if( $age < 1800 )
                continue;
           
            // Hvis opgaven er 30 min gammel, kan vi godt opdatere databasen.
            // Opdater blot status til opgavestatus 2, så du kan sætte den ind på hjemmesiden for rang 3 brugere efter 30 minutter
        }   
       
        if($row->opgavestatus == 2)
        {
            // Igen - her behøver vi ikke foretage os noget, hvis den pågældende opgave ikke er blevet mere end en time gammel
            if( $age < 3600 )
                continue;
           
            // Opdater blot status til opgavestatus 1, så du kan sætte den ind på hjemmesiden for brugere under rang 3 efter en time
        }           
           

        if($row->opgavestatus == 1)
        {
            // Er den fire timer gammel? Ellers hopper vi bare videre...
            if( $age > 14400 )
                continue;
           
            // Send mail ud til alle brugere under rang 4 med opgaven (så brugerne med rang 4 og derover ikke får den samme mail)
            // Opdater status til opgavestatus 0, så du kan sætte den ind på hjemmesiden for alle
        }           

        //Opdater databasen, hvis ikke en 'continue' er mødt
        mysql_query($sql);
       
    }
   
?>
Avatar billede PHPnQrd Nybegynder
27. november 2010 - 10:39 #3
Tak for din gode hjælp.

Men hvad menes der med opgavestatus?

Altså

if($row->opgavestatus == 3)

Fortæller hvis opgavestatus er 3? Den skal jo tælle om den er f.eks. 30 minutter gammel via. timestamp som i databasen hedder "tid".

if ( $row->tid > 30 min) {

eller lign.,

Rangen tjekkes via.

select sum(rang) as rang FROM ratings WHERE tester = 'id'

Kan denne query tilføjes som inner join eller lign., i fornævnte string?
Avatar billede repox Seniormester
27. november 2010 - 22:17 #4
opgavestatus er et feltnavn (et integer) du skal tilføje til tabellen i databasen. Og som jeg skrev i koden, skal alle nystartede opgaver starte med opgavestatus 4.

Min kode er et cronjob, som skal køre hvert minut (eller lignende). Hvert minut vil den så kontrollere opgavens statusnummer og agere ud fra det. Hvis opgaven har status 3, skal den ikke gøre noget før de 30 minutter er gået:
            if( $age < 1800 )
                continue;


Hvordan du kontrollerer rangen, må du selv om - det er nogle ting der skal ind imellem de if-sætninger der bestemmes af af statusopgaven og tiden.
Avatar billede PHPnQrd Nybegynder
29. november 2010 - 12:45 #5
Hej Repox,
Er glad for du gider hjælpe.

Lige p.t, ser mit script sådan her ud - kan du se om det ville virke (Hvis jeg kører cronjob på det hvert 5. min, f.eks):

http://pastebin.com/MxzqEqW6
Avatar billede repox Seniormester
29. november 2010 - 15:46 #6
Dit cronjob vil jo kun gøre noget med opgaverne hvis de er mindst 30 minutter gamle - sender du opgaven til brugere med rating 4+ på en anden måde, så?

Og hvad er det lige du laver på linierne 20-22?

Du laver mangle SQL kald henover de to while løkker.
Hvorfor har du en 'accepteret' tabel? Er der mere end en tester der kan påtage sig opgaven?

Der mangler desuden også noget af koden - din yderste while bliver ikke afsluttet.

Hvorfor kunne du ikke bruge noget af det jeg gav i mit eksempel?
Avatar billede PHPnQrd Nybegynder
29. november 2010 - 19:58 #7
Rating 4 (Dvs. de skal have opgaven med det samme) får den bare tilsendt på samme side når en kunde har oprettet en opgave.

Linje 20-22 tjekker jeg om der er flere "pladser". Da en kunde kan vælge om de f.eks ønsker 20 testere. Så skal den jo ikke sende hvis de er ikke e ledige pladser.

Accepteret -tabellen tjekker om en bruger har accepteret med tidspunkt.


Ved flere ratings, laver jeg en ny fil og ændre sekund-tallet og kører dem hvert 10 min også... Er det en dålig løsning da?

Problemet er, at jeg ikke helt forstår din måde at gøre tingene på.
Avatar billede repox Seniormester
29. november 2010 - 20:38 #8
Måske du skulle forklare hvordan dit ratingsystem fungerer? jeg har ringe forståelse for hvordan dine tabeller er skruet sammen.
Avatar billede PHPnQrd Nybegynder
29. november 2010 - 20:45 #9
Hver gang en kunde rater en tester, indsætter den i tabellen "ratings". Så tager jeg gennemsnittet for hver tester i tabellen for at finde tallet.

SELECT AVG('rating') AS rating FROM ratings WHERE tester = '@id'
Avatar billede repox Seniormester
30. november 2010 - 11:01 #10
Kan jeg ikke få dig til at sende tabelstrukturen for de relevante tabeller - så må jeg lige se om jeg kan lure en løsning.
Avatar billede PHPnQrd Nybegynder
30. november 2010 - 11:17 #11
Selvfølgelig. Har deadline i morgen, så hvis du kan nå at strikke en løsning op, så kvitter jeg naturligvis med lidt penge eller en god vingave.

accepteret:

id - bare ID
tester_id - hvem er testeren der har accepteret eller fået tildelt?
opgave_id - hvilken opgave taler vi om?
accepteret - enten 0 eller 1 . 0 er nej 1 er ja
accepteret_tidspunkt - timestamp (unix), fortæller hvornår testeren trykkede accepter opgave i deres oversigt
done - enten 0 eller 1 = 0 er nej 1 er ja.


ratings:
id - id
kunde - kunde id (hvem har ratet?)
tester - tester id (hvem er testeren?)
opgave - opgave id (hvilken opgave er der tale om?)
rating - hvilken rating er der gået? 1-5


-- her tager jeg gennemsnittet (AVG(..)) for at fange brugerens rating gennemsnit.


test:

antal_test - hvor mange tests ønsker kunden?
kunde_id - hvilken kunde er er der tale om?
afsluttet - 0 eller 1 = 0 er nej 1 er ja
tid - hvornår er testen oprettet (unix time)
oprettet - hvornår er testen oprettet i NOW() format
aktiv - er opgaven aktiv? 0 = nej, 1 = ja
prove - er det en prøvetest? Den skal ikke tage med, hvis prove er 1.
Avatar billede repox Seniormester
30. november 2010 - 11:34 #12
Jeg mente en faktisk tabelstuktur - en export af de tre tabeller fra phpMyAdmin eksempelvis, så jeg har de rigtige felttyper og så videre...
Avatar billede PHPnQrd Nybegynder
30. november 2010 - 12:05 #13
Repox, har sendt link til din e-mail-adresse på err0r.dk til dig, fordi jeg er bange for informationerne bliver leaked. Håber det OK.
Avatar billede repox Seniormester
30. november 2010 - 16:22 #14
Tag lige et kig på det her, så:
http://pastebin.com/CF2AAsqZ
Avatar billede PHPnQrd Nybegynder
30. november 2010 - 19:53 #15
Du er virkelig en guttermand!

I forvejen, tildeler jeg opgaven til alle med rating over 4, så snart den bliver lagt på af kunden.


Dvs. under:

if( $alder < 1800 )

så kan jeg putte ting ind, hvis det er 30 min. siden opgaven er lavet og der stadig ingen accepterede/fuldførte er?

if( $alder > 3600 )

Kan gøre det samme, blot med 1 times interval.


Tjekker den om brugeren i forevejen har accepteret opgaven, så de ikke modtager dobbelt?

Jeg takker virkelig for din super hjælp. Send mig din e-mail, så sende jeg en vingave til dig op til Jul :-)
Avatar billede repox Seniormester
30. november 2010 - 23:51 #16
if( $alder < 1800 )
  continue;

gør ikke andet end springer den aktuelle opgave over, hvis den ikke er mindst en halv time gammel.

if( $alder > 3600 )
  $rating = 0;

sørger blot for at alle, som har en rating med og over 0, skal modtage opgaven, hvis ikke de allerede har modtaget den - ellers vil rating være 3, hvis opgaven er mellem en halv og en hel time gammel.

Og ja, den tjekker om potentielle modtager allerede har modtaget den.

Ellers, tak - jeg nøjes bare med et accepteret svar :)
Avatar billede PHPnQrd Nybegynder
01. december 2010 - 01:43 #17
Kan ikke rigtigt finde ud af din kode.

Kan du hjælpe mig med dette:


Brugere med rating på 3 - tests bliver synlige 30 min efter der er lagt på, hvis der stadig er tests, der ikke er fuldført

Resten - Tests bliver synlig en time efter, hvis der stadig er tests, der ikke er fuldført

Hvis der er gået 4 timer, og der stadig er ledige tests, så udsendes en mail til alle testere (dette virker allerede!)

Også den sidste:

Hvis der er gået 24 timer, og der stadig er ledige tests, så skal den sende en mail til admin.

Hvis du hjælper med dette, har du simpelthen reddet min dag gevaldigt.
Avatar billede PHPnQrd Nybegynder
01. december 2010 - 01:46 #18
Og sidste spørgsmål - hvor tit skal den køre det i cronjob?
Avatar billede PHPnQrd Nybegynder
02. december 2010 - 13:13 #19
Ok, repox, jeg prøvede selv, vil du godkende denne og fortælle om den virker?


http://pastebin.com/4h7Cmzij
Avatar billede repox Seniormester
02. december 2010 - 13:32 #20
Det vil ikke virke - du har mange mangler i både data og indkapslinger. Samtidig ændrer du i logikken og laver duplikerende kode- det er altså lidt svært at holde motivationen oppe til at hjælpe dig færdig med dette, når du laver så meget om i koden; Så vidt jeg kan se - ud fra din kode - er det åbenbart kun nødvendigt at få dit cronjob til at sende en mail ud til dine testere, hvis opgaven er mere end fire timer gammel og den ikke er udført efter kriterierne - hvilket gør det meste af koden overflødig.
Avatar billede PHPnQrd Nybegynder
02. december 2010 - 13:36 #21
Den tjekker om en test er halv time gammel, og tjekker om de allerede har accepteret den og der er ledige pladser derfor send til dem med rating 4.

Den tjekker om en test er en time gammel, og tjekker om de allerede har accepteret den og der er ledige pladser derfor send til dem med rating 3.

Den tjekker om en test er en 4 gammel, og tjekker om de allerede har accepteret den og der er ledige pladser derfor send til alle, og udsend mail med det.

Burde da virke?
Avatar billede PHPnQrd Nybegynder
02. december 2010 - 13:38 #22
Derfor kan den ikke duplicate, da den tjekker om deallerede har modtaget etc.
Avatar billede PHPnQrd Nybegynder
02. december 2010 - 13:47 #23
Jeg har gjort den lidt mere overskuelig, måske du kan spotte hvad jeg gør forkert her: http://pastebin.com/uYhdHvnc
Avatar billede PHPnQrd Nybegynder
02. december 2010 - 13:54 #24
Vil sende dig 500 kr., for din hjælp, hvis du gider få det til at virke.
Avatar billede repox Seniormester
02. december 2010 - 14:34 #25
Jeg skal lige have nogle ting på plads, med det rating og mail halløj, selvom du sikkert synes du har besvaret det et par gange:

1. Du fortæller på et tidspunkt at opgaven bliver sendt ud til brugere med rating 4 og derover når den bliver oprettet. Men i #21 fortæller du at cronjobbet skal, hvis opgaven er mindst en halv time gammel, sende en mail ud til brugere med rating 4, hvis de ikke har påtaget sig opgaven. Hvad er det præcist der skal ske efter en halv time?

2. Hvad skal der præcist ske efter en time?

3. Og hvad skal der præcist ske når den er 4 timer gammel?
Avatar billede PHPnQrd Nybegynder
02. december 2010 - 14:56 #26
Sendt ud, mener jeg den havner i deres oversigt når de logger ind, har lige hørt fra "the boss", at den kun skulle udsende en EMAIL når det er mere end 4 timer siden.

Dvs. halv time gammel, tilføj til "brugertest_accepteret( ... ) " og IKKE send e-mail.

Samme med efter en time.

Blot effter 4 timer, skal den både indsætte i accepteret-databasen samt sende mail ud til alle testerne :)
Avatar billede repox Seniormester
02. december 2010 - 15:02 #27
Så 'brugertest_accepteret' tabellen, bruges til at vise opgaverne på testernes oversigt og er egentlig ikke en indikation på at en bruger har accepteret en opgave?
Avatar billede PHPnQrd Nybegynder
02. december 2010 - 15:07 #28
Jo, begge dele, den har et kolonne der hedder "accepteret", som er 1 hvis de har acceperet og 0 hvis de kun har modtaget den, men ikke accepteret :-)
Avatar billede repox Seniormester
02. december 2010 - 16:09 #29
Prøv lige denne her:
http://pastebin.com/H4WP5fMj
Avatar billede PHPnQrd Nybegynder
02. december 2010 - 17:14 #30
Ser rigtigt ud :-) Har dog ikke testet fuldsændigt endnu, men den melder ikke fejl og den outputter ting, så tror det lykkedes.

Kan man lave en if-sætning der siger:

hvis der er gået 24 timer og der stadig er ledige tests, så skal den sende en e-mail til adminisrator?
Avatar billede repox Seniormester
02. december 2010 - 22:54 #31
Mjaeh, ikke uden at ændre tabel strukturen, så du kan fortælle cronjobbet at admin allerede har fået en mail - ellers vil du jo i princippet modtage en email for hver gang cronjobbet kører indtil der ikke er flere ledige tests på den pågældende opgave.

Så jo, det er da muligt - men så skal du lave et felt mere i din brugertest_test tabel til at kontrollere op imod...
Avatar billede PHPnQrd Nybegynder
06. december 2010 - 12:38 #32
Dvs.


if( $alder > 86400 ) // 24 timer
{
    //tjek om der sadig er ledige og tjek om mail allerede er sendt il admin

    if ( mail ikke sendt ) {
            send
    }
}
Avatar billede repox Seniormester
06. december 2010 - 12:42 #33
Ja - noget i den stil; men du mangler naturligvis stadig det hvor du opdaterer tabellen som fortæller om der faktisk er sendt en mail ud til admin eller ej.
Avatar billede PHPnQrd Nybegynder
06. december 2010 - 12:49 #34
Ok, men så hvis jeg kører cronjob hver 10 min., bliver den vel ved med at udsende mails til testerne?


if ( $sendmail == 1 )
{
                                                        $tjekModtaget = mysql_query("SELECT id FROM brugertest_harmodtaget WHERE opgave = '".$opgave['id']."' AND bruger = '".$bruger['id']."'");
                                                        if ( mysql_num_rows($tjekModtaget)==0) {
                      $htmlMail = file_get_contents("mailheader.php");
                      mail($bruger['email'], "Der er ny brugertest klar!", $htmlMail, $header);
                                                              mysql_query("INSERT INTO brugertest_harmodtaget (opgave, tester) VALUES ('".$opgave['id']."','".$bruger['id']."')");
                                                      } else { }
Avatar billede repox Seniormester
06. december 2010 - 12:51 #35
Ikke så længe kriteriet var at hvis de står i brugertest_accepteret tabellen, så skal de ikke modtage nogen mails.
Avatar billede PHPnQrd Nybegynder
07. december 2010 - 12:07 #36
Tak Repox. Har oprettet et nyt spørgsmål lign. dette også. Send mig din email så sender jeg dig 500 kr.
Avatar billede Ny bruger Nybegynder

Din løsning...

Tilladte BB-code-tags: [b]fed[/b] [i]kursiv[/i] [u]understreget[/u] Web- og emailadresser omdannes automatisk til links. Der sættes "nofollow" på alle links.

Loading billede Opret Preview
Kategori
Vi tilbyder markedets bedste kurser inden for webudvikling

Log ind eller opret profil

Hov!

For at kunne deltage på Computerworld Eksperten skal du være logget ind.

Det er heldigvis nemt at oprette en bruger: Det tager to minutter og du kan vælge at bruge enten e-mail, Facebook eller Google som login.

Du kan også logge ind via nedenstående tjenester