Technische Umsetzung für Warenkorb mit Sessions

Einklappen
X
 
  • Filter
  • Zeit
  • Anzeigen
Alles löschen
neue Beiträge

  • Technische Umsetzung für Warenkorb mit Sessions

    Hallo zusammen,

    ich Bastel gerade an einer art Shop und bin beim Warenkorb und bei der Bestellabwicklung angekommen. Jetzt habe ich ein paar Fragen bezüglich Sessions, habe vorher nie mit Sessions gearbeitet.

    Ich starte in meiner index.php, die Ausgangspunkt für die Abarbeitung des Auftritts ist, eine Session mit session_start(). Jetzt wird ein Cookie angelegt, der bis zum Sitzungsende Aktiv ist, also bis der Browser geschlossen wird.

    Hier stellt sich mir die Frage, ob es die eleganteste Lösung ist, oder ob ich die Lebensdauer des Session-Cookies erhöhen sollte? Wobei meine Sessions wahrscheinlich auch nicht solange gespeichert werden.

    In dem "Shop" kann man nicht einfach durch Artikel Browsen, sondern es wird über ein Suchfeld ein String eingegeben, der in der Datenbank gesucht wird und falls gefunden ausgegeben wird, dies kann man dann in den Warenkorb legen. Der Warenkorb basiert jetzt quasi nur auf Sessions, also sobald ein Benutzer etwas in den Warenkorb legt, wird ein neuer Eintrag in der Session abgelegt:

    PHP-Code:
    <?php
    if($_SERVER['REQUEST_METHOD'] == 'POST')
    {
        
        
    $articleid trim($_POST['articleid']);
        
        
    /*...
        überprüfung ob produktid valide ist (abgleich in DB)
        ...*/

        
    $product = .....;

        if(isset(
    $_SESSION['cart']))
        {
            if(!
    array_key_exists($articleid$_SESSION['cart']))
            {
                
    $_SESSION['cart'][$articleid] = $product;
                return 
    'erfolgreich hinzugefügt';
            }
            else
            {
                return 
    'befindet sich bereits im warenkorb';
            }
        }
        else
        {
            
    $_SESSION['cart'][$articleid] = $product;
            return 
    'erfolgreich hinzugefügt.';
        }
        
    }
    else
    {
        return 
    'ohne post keine produkte';
    }
    ?>
    Soweit so gut, das Funktioniert auch Prima, wenn ich jetzt ein count() auf $_SESSION['cart'] gebe, wird mir auch die Anzahl der bereits in der Session stehenden Artikel ausgegeben.

    So jetzt zu meinem eigentlich Problem, der Warenkorb selber.

    Sobald ich auf den Warenkorb gehe, möchte ich natürlich meine Artikel schön aufgelistet bekommen, was natürlich kein problem darstellt. Allerdings möchte ich Artikel wieder löschen können und da "hapert" es momentan. Ich habe zwar eine Lösung dafür die auch soweit funktioniert, aber die ist leider nicht das Gelbe vom Ei.

    Ausgabe der Artikel (Noch nicht ganz fertig).

    PHP-Code:
    <?php
    if(isset($_SESSION['cart']))
    {
        foreach(
    $_SESSION['cart'] as $articleid => $detail)
        {
        
    ?>
            <form action="" method="POST">
                <li> <?=$detail;?>
                    <input type='submit' value='löschen' name='delete' />
                    <input type='hidden' value='<?=$detail;?>' name='articleid' />
                </li>
            </form>
        <?php
        
    }
    }
    else
    {
        echo 
    'keine artikel vorhanden';

    ?>
    Ich denke ihr seht das Problem von der HTML Umsetzung. Ich möchte nicht soviele Formulare haben, das muss auch anders gehen.

    Die technische Seite, wobei die auch noch nicht so das Wahre ist:

    PHP-Code:
    <?php
    if($_SERVER['REQUEST_METHOD'] == 'POST')
    {

        
    $data $_POST['delete'];
        
    $articlelid $_POST['articleid'];

        
    /* ...
        produkt validierung mit DB
        ...*/

        
    switch($data)
        {
            case 
    'löschen':
                unset(
    $_SESSION['cart'][$articleid]);
                return 
    'Artikelnummer: ' $articleid ' sollte jetzt gelöscht sein';
                break;
            
    /* weitere cases */
            
    default:
                return 
    'fehler aufgetreten';
                break;
        }
    }
    ?>
    Also ich kann mir gerade nicht vorstellen, dass das so funktioniert, vielleicht habe ich auch einfach eine Denkblockade, ich weiß es nicht.

    Ich dachte mir noch sowas:
    Wenn ich per JavaScript den Löschen Link/Button/Grafik klicke, dass der Artikel im Warenkorb verschwindet (display: none, aber wie bekomme ich den dann am besten aus der Session raus?

    Vielleicht hat ja jemand eine gute Lösung dafür, aber bitte nicht schreiben das man eine fertige Shopsoftware nutzen soll.

    Und Allgemein wäre natürlich noch gut zu Wissen, ob das ganze so ok ist, oder ob man das vergessen kann/anders macht. Hab dazu nicht allzuviel im Internet gefunden.

    Ach und nochwas... Wenn ich eine Session Starte und die 30 Minuten Lebenszeit hat, ein Benutzer 5 Minuten nichts macht und auf ne andere Seite geht (Innerhalb meiner Seite), dann wird die Session ja wieder aufgenommen, aber wird die Lebensdauer dann auch wieder auf 30 Minuten gesetzt, oder hat die trotzdem nur noch 25 Minuten?

    LG
    Pit
    Zuletzt geändert von PitPanda; 15.10.2011, 22:31. Grund: Nachtrag

  • #2
    Hallo,

    du kannst du beim Bearbeiten des Warenkorbs ein einziges Formular nehmen und darin alle Artikel mit einer Lösch-Checkbox unterbringen oder einem Textfeld, in dem man die Menge ändern und natürlich auch auf 0 setzen kann, so wie viele große Shops es machen. Guck dir doch einfach bei denen mal den HTML-Quelltext an. Daraus kannst du ja einiges zum Grundaufbau lernen. Auch wenn du natürlich den PHP-Code nicht siehst, kannst du die Struktur erkennen.

    Gruß,

    Amica
    [COLOR="DarkSlateGray"]Hast du die [COLOR="DarkSlateGray"]Grundlagen zur Fehlersuche[/color] gelesen? Hast du Code-Tags benutzt?
    Hast du als URL oder Domain-Beispiele example.com, example.net oder example.org benutzt?
    Super, danke!
    [/COLOR]

    Kommentar


    • #3
      Hm, ja habe mir den Aufbau bei den Großen angeschaut, das ist eigentlich nicht so das Problem. Mit dem Haken würde es gehen, oder wenn man eine Menge angibt, stimmt, allerdings gefällt mir das als Lösung nicht so.

      Habe aber bei einem gesehen, dass ein Ajax abgesendet wird, eventuell mache ich das auch so und bei erfolg ein Refresh auf die Seite.

      Aber mit dem unset() kann man arbeiten, um einen Eintrag aus dem Session Array zu löschen? Oder gibt es da eine bessere Lösung?



      ---

      Ok habe es jetzt mal mit AJAX versucht, jetzt habe ich das Problem, dass ich in dem Script abfangen muss, ob die Anfrage halt ein AJAX "Request" ist, wie stellt man das denn an? Habe mir den Header angeschaut, was ich mir vorstellen kann irgendwie auf "X-Requested-With XMLHttpRequest" zu prüfen, aber wo steht das drin?
      Zuletzt geändert von PitPanda; 15.10.2011, 23:35.

      Kommentar


      • #4
        Deine Seite sollte auch ohne JS funktionieren.
        Also vergiss Ajax erstmal wieder.

        Und ja, die Sessionlaufzeit verlängert sich bei jedem Request auf deine Seite wieder auf die voreingestellte Zeit.

        Was hast du gegen unset()?
        Was sollte es bequemeres geben?



        Hier mal ein primitiver Warenkorb aus meiner Bastelkiste:
        PHP-Code:
        <?php
        error_reporting
        (E_ALL|E_STRICT); 
        ini_set('display_errors'TRUE); 


        $vorrat   = array();
        $vorrat[] = 'hemd';
        $vorrat[] = 'pulli';
        $vorrat[] = 'nagel';


        class 
        Warenkorb implements Countable
        {

          private 
        $inhalt = Array();

          public function 
        hinzufuegen($artikel)
          {
            if (isset(
        $this->inhalt[$artikel]))
            {
              
        $this->inhalt[$artikel]++;
            }
            else
            {
              
        $this->inhalt[$artikel] = 1;
            }
          }
          public function 
        count()
          {
            return  
        count($this->inhalt);
          }

          public function 
        entfernen($artikel)
          {
            if (isset(
        $this->inhalt[$artikel]))
            {
              if(
        $this->inhalt[$artikel]<=1)
                  unset(
        $this->inhalt[$artikel]);
               else 
        $this->inhalt[$artikel]--;
            }

          }

          public function 
        leeren()
          {
            
        $this->inhalt = Array();
          }

          public function 
        gibkorb()
          {
            return 
        $this->inhalt;
          }
        }

        session_start();


        if(!isset(
        $_SESSION['korb']))
        {
          
        $_SESSION['korb'] = new Warenkorb;
        }
        elseif(!(
        $_SESSION['korb'] instanceof Warenkorb))
        {
          throw new 
        Exception('Warenkorb kaputt (schon mit was anderm belegt)');
        }

        if(isset(
        $_GET['artikel']))
        {
          
        $_SESSION['korb']->hinzufuegen($_GET['artikel']);
        }

        if (isset(
        $_GET['entf']))
        {
          
        $_SESSION['korb']->entfernen($_GET['entf']);
        }

        if (isset(
        $_GET['loeschen']))
        {
           
        $_SESSION['korb']->leeren();
        }
        ?>
        <html>
            <body>
                <h1>Warenkorb</h1>
                <a href="?loeschen=1">Warenkorb löschen</a> <br>
        <?php
        if(count($_SESSION['korb']))
        {
          print 
        "Sie haben folgende Artikel ausgewählt:<br> ";
          foreach (
        $_SESSION['korb']->gibkorb() as $artikel => $anzahl)
          {
            print 
        "Artikel $artikel Anzahl: $anzahl  ";
            print 
        "<a href='?entf=$artikel'>";
            print 
        "Artikel entfernen</a><br>";
          }
        }else
        {
          print 
        "Bisher nichts ausgewählt";
        }

        print 
        "    <h1>Folgende Artikel können Sie bestellen</h1>";
        foreach(
        $vorrat as $ding)
         print 
        "<a href='?artikel=$ding'>$ding in Warenkorb legen</a><br>";
        ?>

          </body>
        </html>
        Wir werden alle sterben

        Kommentar


        • #5
          Ahh, ok. Mir war nicht bewusst, dass man in einer Session Objekte ablegen kann. Dann mache ich das auch mit einer Klasse, danke für den Hinweis. Hatte es jetzt mit AJAX gemacht, dann lad ich einfach die Seite neu, sollte auch passen.

          Kommentar


          • #6
            Falls du später doch nochmal mit AJAX arbeitest: X-Requested-With ist Blödsinn. Zu unterscheiden, ob ein Request klassisch erfolgt ist oder im Hintergrund mit AJAX ist ebenfalls Blödsinn.

            Alles, was wichtig ist, ist welche Daten übermittelt werden und welche Daten erwartet werden. Willst du eine HTML-Seite ausliefern, weil ein Benutzer gerade auf die Seite geht und sein Browser die entsprechende URL anfordert, wird dieser Browser dich bevorzugt nach text/html und application/xhtml+xml fragen. Also lieferst du es.

            Wenn ein Hintergrund-Request aus einer Webapplikation JSON-Daten anfordert, dann soll er auch nach application/json fragen, dein PHP-Script kann dann JSON ausliefern. Das alles macht man über den Accept-Header.

            Es macht also keinen Sinn, zu unterscheiden, ob ein Request klassisch oder mit AJAX geschickt wurde. Es ist besser, danach zu unterscheiden, was der Client gerade für Daten haben möchte.
            [COLOR="DarkSlateGray"]Hast du die [COLOR="DarkSlateGray"]Grundlagen zur Fehlersuche[/color] gelesen? Hast du Code-Tags benutzt?
            Hast du als URL oder Domain-Beispiele example.com, example.net oder example.org benutzt?
            Super, danke!
            [/COLOR]

            Kommentar


            • #7
              Stimmt, habe allerdings bisher auch noch nicht mit JSON gearbeitet.

              Habe jetzt 2 Klassen erstellt, einmal Warenkorb und einmal Artikel.


              Warenkorb Klasse
              PHP-Code:
              <?php
              class cart_shoppingcart
              {
                  
                  protected 
              $articles = array();
                  protected 
              $db;
                  
                  public function 
              __construct($db null)
                  {
                      if(!
              is_null($db))
                      {
                          
              $this->db $db;
                      }
                  }
                  
                  public function 
              getArticleCount()
                  {
                      return 
              count($this->articles);
                  }
                  
                  
                  public function 
              addArticle($articleid)
                  {
                      if(!isset(
              $this->articles[$articleid]))
                      {
                          if(
              $this->validateArticle($articleid))
                          {
                              
              $this->articles[$articleid] = new cart_article($articleid$this->db);
                              return 
              'artikel hinzugefügt';
                          }
                          else
                          {
                              return 
              'artikel gibt es nicht';
                          }
                      }
                      else
                      {
                          return 
              'schon im warenkorb';
                      }
                  }
                  
                  public function 
              deleteArticle($articleid)
                  {
                      if(isset(
              $this->articles[$articleid]))
                      {
                          unset(
              $this->articles[$articleid]);
                          return 
              'gelöscht';
                      }
                      else
                      {
                          return 
              'artikel nicht vorhanden';
                      }
                  }
                  
                  private function 
              validateArticle($articleid)
                  {
                      
                      
              $sql "SELECT
                                  id
                              FROM
                                  report
                              WHERE
                                  id = ?"
              ;
                      
                      
              $stmt $this->db->prepare($sql);    /*  Zeile 65  */
                      
              $stmt->bind_param("i"$articleid);    /*  Zeile 66  */
                      
              $stmt->execute();
                      
              $stmt->bind_result($id);
                      
              $stmt->fetch();

                      if(!empty(
              $id))
                      {
                          return 
              true;
                      }
                      else
                      {
                          return 
              false;
                      }

                  }
                  
                  public function 
              getArticle($articleid)
                  {
                      return 
              $this->articles[$articleid];
                  }
                  
                  public function 
              getAll()
                  {
                      return 
              $this->articles;
                  }
                  
              }
              Artikel Klasse
              PHP-Code:
              <?php
              class cart_article
              {

                  public 
              $articleid;
                  public 
              $vin;
                  public 
              $brand;

                  public function 
              __construct($articleid$db)
                  {

                      
              $sql "SELECT
                                  *
                              FROM
                                  report
                              WHERE
                                  id = ?"
              ;

                      
              $stmt $db->prepare($sql);
                      
              $stmt->bind_param("i"$articleid);
                      
              $stmt->execute();
                      
              $stmt->bind_result($id$vin$brand);
                      
              $stmt->fetch();

                      
              $this->articleid $id;
                      
              $this->vin $vin;
                      
              $this->brand $brand;

                  }

              }
              Muss da leider meine Datenbankverbindung mit übergeben, habe bisher noch mit mysqli gearbeitet, müsste das mal auf PDO umstellen.

              Muss ich nur rausfinden wie ich am besten die Artikel löschen lassen kann.

              Artikel Klasse, weil ich die nacher noch verwenden möchte, also die bekommt noch ein paar methoden.



              ---

              Hmm jetzt habe ich doch ein Problem.

              Artikel hinzufügen

              PHP-Code:
              if($_SERVER['REQUEST_METHOD'] == 'POST')
              {    
                  
                  
              $id trim($_POST['id']);

                  if(isset(
              $_SESSION['cart']))
                  {
                      if(!(
              $_SESSION['cart'] instanceof cart_shoppingcart))
                      {
                          
              $_SESSION['cart'] = new cart_shoppingcart($db);
                          return 
              $_SESSION['cart']->addArticle($id);
                      }
                      else
                      {
                          return 
              $_SESSION['cart']->addArticle($id);
                      }        
                  }
                  else
                  {
                      
              $_SESSION['cart'] = new cart_shoppingcart($db);
                      return 
              $_SESSION['cart']->addArticle($id);
                  }
                  
              }
              else
              {
                  return 
              'wurde nichts gefunden';

              Klassen stehen ja oben. Und zwar kann ich den ersten Artikel wunderbar hinzufügen und auch kein zweitesmal etc., allerdings kann ich keine weiteren Artikel hinzufügen:

              Fehler:
              PHP-Code:
              Warning:  mysqli::prepare() [mysqli.prepare]: Couldn't fetch mysqli in /web/1/000/058/157/235491/htdocs/next/application/cart/shoppingcart.class.php on line 65
              Fatal error:  Call to a member function bind_param() on a non-object in /web/1/000/058/157/235491/htdocs/next/application/cart/shoppingcart.class.php on line 66 
              Ich seh irgendwie den Fehler grade nicht, habe die Zeilen markiert (Warenkorb Klasse).

              Ausgabe

              PHP-Code:
              <ul>
                  <form action="" method="POST">
                      <?php
                      
                          
              if(isset($_SESSION['cart']))
                          {
                              foreach(
              $_SESSION['cart']->getAll() as $article => $detail)
                              {
                              
              ?>
                                  <li> <?=$detail->vin;?> <?=$detail->brand;?> 
                                      <a href="#" class="delete">Löschen</a>
                                      <input type='hidden' class="productid" value="<?=$detail->articleid;?>" name='vin' />
                                  </li>
                              <?php
                              
              }
                          }
                          else
                          {
                              echo 
              '<li>Es Befinden sich keine artikel im warenkorb</li>';
                          }
                      
              ?>
                  </form>
              </ul>
              Zuletzt geändert von PitPanda; 16.10.2011, 14:28.

              Kommentar


              • #8
                PHP-Code:
                 $this->db $db
                Du kannst keine Ressourcen in Sessions speichern.
                Sie gehen am Scriptende verloren.
                Wir werden alle sterben

                Kommentar


                • #9
                  Jep danke, hab ich gemerkt.

                  Ich mache es jetzt so das ich mir eine DB Klasse baue die mir mit singletone eine Instanz von der db gibt, hoffe das funzt dann.

                  Kommentar


                  • #10
                    Zitat von PitPanda Beitrag anzeigen
                    Jep danke, hab ich gemerkt.

                    Ich mache es jetzt so das ich mir eine DB Klasse baue die mir mit singletone eine Instanz von der db gibt, hoffe das funzt dann.
                    Singleton ist schlechter Stil. Mach dich über Dependency Injection schlau.

                    Kommentar


                    • #11
                      Hm daraus werde ich gerade noch nicht schlau. Da müsste ich die ganze Seite quasi umbauen, das mach ich dann bei Zeiten mal. Habe es jetzt wie oben geschrieben gemacht, was soweit gut funktioniert. Jetzt probiere ich mich an der Bestellung mit Menüführung. Danke für die Hilfe.

                      Kommentar


                      • #12
                        Zitat von PitPanda Beitrag anzeigen
                        Jep danke, hab ich gemerkt.

                        Ich mache es jetzt so das ich mir eine DB Klasse baue die mir mit singletone eine Instanz von der db gibt, hoffe das funzt dann.
                        Hallo,

                        erkläre mir mal bitte den Sinn einer Singleton DB Instanz?

                        Davon mal abgesehen, nicht in jedem Fall ist Singleton schlechter Stil. Beispiele sind ein Auth Object. Man braucht in einer Anwendung nun mal nur eine einzige Auth Instanz pro User, warum also da kein Singleton? Oder einen Frontcontroller, auch da braucht man nur einen, also warum keine Singleton FrontController Instanz bilden?
                        Also ganz so ist es ja nun nicht das dies schlechter Stil ist, diese Aussage ist einfach falsch. Aber man muss es wirklich sinnvoll einsetzen und da hapert es meistens, siehe Beispiel Singleton DB Instanz.

                        Was wenn es mal nötig wird das ne SQLLite mit hinzukommt für gewisse Sachen? Dann bist mit deinem Singleton vollkommen im Ar....., denn dann kannst nämlich keine 2 Instanz auf ne SQLLite DB anlegen.

                        Zu den ganzen anderen Sachen kann ich nicht viel sagen weil ich mir das nicht ganz angeschaut habe.
                        Aus dem Dynamo Lande kommen wir. Trinken immer reichlich kühles Bier. Und dann sind wir alle voll, die Stimmung ist so toll. Aus dem Dynamo Lande kommen wir.
                        http://www.lit-web.de

                        Kommentar


                        • #13
                          Zitat von litterauspirna Beitrag anzeigen
                          Davon mal abgesehen, nicht in jedem Fall ist Singleton schlechter Stil. Beispiele sind ein Auth Object. Man braucht in einer Anwendung nun mal nur eine einzige Auth Instanz pro User, warum also da kein Singleton? Oder einen Frontcontroller, auch da braucht man nur einen, also warum keine Singleton FrontController Instanz bilden?
                          Singletons sind schwer bis gar nicht testbar. Deswegen sollte man sie vermeiden, wo es nur geht.

                          Warum muss ein Front Controller ein Singleton sein? Ich seh keinen Grund dafür. Welche Vorteile erhoffst du dir davon?

                          Kommentar


                          • #14
                            Oder einen Frontcontroller, auch da braucht man nur einen, also warum keine Singleton FrontController Instanz bilden?
                            Weil Singletons feste Abhängigkeiten mit in die Applikation bringen.
                            Und gerade eben der Frontcontroller wird meist von einer Basisklasse, eines Frameworks, abgeleitet und ist (fast) zwangsweise in jeder Applikation anders aufgebaut.

                            Merksatz 1:
                            Ob irgendwas Singleton sein darf/muss ist eine Anforderung der konkreten Anwendung.

                            Merksatz 2:
                            Feste Abhängigkeiten stören bei der Vererbung.

                            Umkehrschluss:
                            Niemals darf in einer Klassensammlung/Framework irgendwas als Singleton definiert werden.

                            Selbst die Leute vom ZF haben das mittlerweile geschnasselt und werden (vermutlich) ALLE Singletons aus dem ZF2 entsorgen. Nicht ohne Grund.
                            Wir werden alle sterben

                            Kommentar

                            Lädt...
                            X