Neue Klasse für schnelles Blättern im Backend Ver. >= 4.

Gesperrt
devils.fist
Beiträge: 24
Registriert: Fr 5. Aug 2005, 10:20
Wohnort: Wolfsburg
Kontaktdaten:

Neue Klasse für schnelles Blättern im Backend Ver. >= 4.

Beitrag von devils.fist » Do 23. Feb 2006, 11:26

Hallo,

vielleicht ist es ja nicht nur mir aufgefallen, daß wenn man durch große Datenbestände blättern will, z.B. bei den eingerichteten Usern, es sehr lange dauert bis etwas angezeigt wird. Das liegt hauptsächlich daran, daß erst alle Benutzer aus der Datenbank ausgelesen werden und danach nur eine bestimmte Anzahl angezeigt wird.

Folgende Klasse schafft da Abhilfe. Um sie zu nutzen muss der Code natürlich angepasst werden, ist aber nicht allzu wild. Zuerst wird ganz normal eine Klasse von Typ ItemCollection (oder eine Abgeleitete) initialisiert, und die Sortierreihenfolge, etc. gesetzt.
Dann kann mittels der Funktion queryFromItemCollection der neuen Klasse das Ergebnis generiert werden. Die Sortierung und Limitierung übernimmt hier die Datenbank. Das Ergebnis wird in der _data Variable der Klasse gespeichert und kann weiterverwendet werden.

Der Code ist relativ gut dokumentiert und kann auch mittels Doxygen ausgelesen werden.

Klasse FastBackendList:

Code: Alles auswählen

<?php

/** Klasse fastBackendScrollList
  *
  * Eigene Implementierung im Stil der cScrollList (nur schneller)
  *
  * @author Florian Born
  */

class fastBackendScrollList extends cScrollList
{
   var $query;          ///< Speichert die DB-Abfrage zum Erstellen der Liste
   var $db;             ///< Datenbankinstanz zum Ausführen der Query
   var $recordCount;    ///< Speichert Anzahl der Datensätze
   var $recordsPerPage; ///< Anzahl der Einträge pro Seite
   var $currentPage;    ///< Aktuelle Seite
   var $numPages;       ///< Anzahl der Seiten

   /** Konstruktor
     * \param rpp Integer recordsPerPage - Anzahl der Einträge pro Seite - Standard = 25
     */

   function fastBackendScrollList($rpp = 25)
   {
      parent::cScrollList();
      $this->db = new DB_Contenido();
      $this->recordsPerPage = $rpp;
      $this->currentPage=1;
   }

   /** Aktuelle Seite zum anzeigen angeben
     * \param page Integer
     */
   
   function setCurrentPage($page)
   {
      $this->currentPage = $page;
   }
   
   /// Gibt aktuelle Seite zurück

   function getCurrentPage()
   {
      return $this->currentPage;
   }
   
   /// Gibt die Gesamtseitenanzahl zurück
   
   function getNumPages()
   {
      return $this->numPages;
   }
   
   /** Anzahl der Einträge pro Seite setzen
     * \param rpp Integer
     */
   function setResultsPerPage($rpp)
   {
      $this->recordsPerPage = $rpp;
   }


   /** Query setzen
     * \param query String Komplette Abfrage (SELECT ... FROM ... WHERE ... [GROUP|ORDER] BY)
     */

   function setQuery($query)
   {
      $this->query = $query;
   }

   /** Holt die Ergebnisse
     * \param oCol ItemCollection
     * Original Code von Timo Hummel, four for business AG (www.4fb.de)
     */

   function queryFromItemCollection($oCol)
   {
      $groupWhereStatements 	= $oCol->_buildGroupWhereStatements();
		$whereStatements      	= $oCol->_buildWhereStatements();
		$parameters				   = $oCol->_fetchJoinTables(get_class($oCol));

      $statement = array(	"SELECT",
							"*",
							"FROM",
							$oCol->table . " AS ".strtolower(get_class($oCol)));

		if (count($parameters["tables"]) > 0)
		{
			$statement[] = implode(", ", $parameters["tables"]);
		}

		if (count($parameters["joins"]) > 0)
		{
			$statement[] = implode(" ", $parameters["joins"]);
		}

		$wheres = array();

		if (count($parameters["wheres"]) > 0)
		{
			$str = implode(", ", $parameters["wheres"]);
         $wheres[] = str_replace('%25','%',$str);
		}

		if ($groupWhereStatements != "")
		{
			$str = $groupWhereStatements;
			$wheres[] = str_replace('%25','%',$str);
		}

		if ($whereStatements != "")
		{
			$str = $whereStatements;
			$wheres[] = str_replace('%25','%',$str);
		}

		if (count($wheres) > 0)
		{
			$statement[] = "WHERE ".implode(" AND ", $wheres);
		}

		if ($oCol->_order != "")
		{
			$statement[] = "ORDER BY ".$oCol->_order;
		}

      $sql = implode(" ", $statement);

      $this->query = $sql;
      $this->getResults(false);
   }


   /** Tabellenheader setzen
     * \param header Array - Bsp.: Array("Name", "Adresse", "Email", ...)
     */

   function setHeader($header)
   {
      if (!is_array($header))
         die ("Error in class ".get_class($this)."::setHeader : Übergebener Header ist kein Array");
      $this->header = $header;
   }

   /** Interne Funktion
     */
   function getLimit()
   {
      return ($this->recordsPerPage * ($this->currentPage-1)).",".$this->recordsPerPage;
   }
   
   /** Funktion zum generieren der Tabelle mit Header und Seitenwechsellinks
     * wird direkt von QueryFromItemCollection aufgerufen
     * \param return bool Ausgabe zurückgeben oder in interne Variable speichern? Standard = speichern
     */

   function getResults($return = false)
   {
      $this->db->query($this->query);
      $this->recordCount = $this->db->num_rows();

      if ($this->recordCount > $this->recordsPerPage)
         $this->db->query($this->query." LIMIT ".$this->getLimit());

      $this->numPages = ceil($this->recordCount / $this->recordsPerPage);

      $this->query = $this->query." LIMIT ".$this->getLimit();

      $cnt = 0;
      while ($this->db->next_record())
      {
         $arr = $this->db->copyResultToArray();
         foreach ($arr as $key => $value)
         {
            $arr[$key] = urldecode($value);
         }
         $resultArr[$cnt] = $arr;
         $cnt++;
      }
      if ($return)
         return $resultArr;
      else
         $this->_data = $resultArr;
   }
   
   function getNumResults()
   {
      return $this->recordCount;
   }
/* Sollte nicht mehr gebraucht werden

   function updateCScrollList($oSL)
   {
      if (get_class($oSL) != 'cscrolllist')
         die ("Falsche Klasse für updateCScrollList. Muss vom Typ cScrollList sein");
      else
      {
         //$oSL->listStart = $this->currentPage;
         $oSL->numPages = $this->numPages;
         return $oSL;
      }
   }
*/
}

?>
Beispiel für die Verwendung:

Code: Alles auswählen

$oList = new fastBackendScrollList;
// set paging
if ($_GET['action'] == 'pageNav')
{
   $oList->setCurrentPage($_GET['page']);
} else
{
   $oList->setCurrentPage(1);
}

$oList->setResultsPerPage(25);

$oTeile = new tApiTeileverwaltung;
$oTeile->setWhere('tApiTeileverwaltung.idclient', $client);
...
$header = Array('Spalte1', 'Spalte2',...);

$oList->setHeader($header);
$oList->queryFromItemCollection($oTeile);
if ($oList->getNumResults() == 0)
{
	$oList->setData(0, 'keine Daten',...);
}
else
{
   $cnt = 0;
   foreach ($oList->_data as $key => $value)
   {
      $oList->setData($cnt, $value['data1'], $value['data2'], ...);
      $cnt++;
   }
}
$oList->render();

HerrB
Beiträge: 6935
Registriert: Do 22. Mai 2003, 12:44
Wohnort: Berlin
Kontaktdaten:

Beitrag von HerrB » Mo 27. Feb 2006, 17:48

Der Grund, warum erst alles aus der DB geholt, dann sortiert und anschließend ggf. begrenzt ausgegeben wird, ist der Versuch, unabhängig von mySQL zu werden. Sobald Du LIMIT verwendest, ist das nicht mehr gegeben.

Ich stimme Dir zu, dass der jetzige Ansatz unter Performance-Gesichtspunkten suboptimal ist... :wink:

Um eine Sortierung bzw. ein Limit zu erreichen, hätte es genügt, bei einem ItemCollection-Objekt setOrder und setLimit zu verwenden. Auf dem direkten Weg (über die Funktion select) wäre es der letzte Parameter gewesen.

Ansonsten: Schöne Arbeit !

Gruß
HerrB
Bitte keine unaufgeforderten PMs oder E-Mails -> use da Forum!

Newsletter: V4.4.x | V4.6.0-15 (Module, Backend) | V4.6.22+
Standardartikelliste: V4.4.x | V4.6.x
http://www.contenido.org/forum/search.php | http://faq.contenido.org | http://www.communido.net

Gesperrt