WBCE CMS – Way Better Content Editing.
You are not logged in.
Hallo,
die aktuelle Datenbank Klasse ist ja funktional stark eingeschränkt. Man kann keine "Params binden" (verhindert SQL Injection), keine "Transaktionen" auslösen usw.
Ist geplant in Zukunft PDO zu nutzen? Alternativ hätte ich sonst noch eine leicht abstrahierte, selber geschriebene, Datenbank Klasse mit einem Query Counter auf Basis von PDO.
Soll ich meine unten angegebene Klasse mal soweit anpassen, damit auch die alten WB-Datenkank Methoden gehen? Dann würde alles wie bisher funktionieren und wir könnten endlich für neue Entwicklungsarbeiten die Vorteile der PDO Funktionen nutzen.
[== PHP ==]
class Database extends \PDO
{
/**
* @var int
*/
protected $numberOfQueries = 0;
/**
* Prepares a statement for execution and returns a statement object.
*
* @param string $statement
* @param array $options
*
* @return PDOStatement
*/
public function prepare($statement, $options = array())
{
$this->numberOfQueries += 1;
return parent::prepare($statement, $options);
}
/**
* Executes an SQL statement, returning a result set as a PDOStatement object.
*
* @param string $query
*
* @return PDOStatement
*/
public function query($query)
{
$this->numberOfQueries += 1;
return parent::query($query);
}
/**
* Execute an SQL statement and return the number of affected rows.
*
* @param string $statement
*
* @return int
*/
public function exec($statement)
{
$this->numberOfQueries += 1;
return parent::exec($statement);
}
/**
* Get number of executed queries.
*
* @return int
*/
public function getNumberOfQueries()
{
return $this->numberOfQueries;
}
}
Last edited by rjgamer (21.06.2016 12:43:41)
Offline
Soll ich meine unten angegebene Klasse mal soweit anpassen, damit auch die alten WB-Datenkank Methoden gehen? Dann würde alles wie bisher funktionieren und wir könnten endlich für neue Entwicklungsarbeiten die Vorteile der PDO Funktionen nutzen.
Ich würde es begrüßen.
Bitte schreib NorHei eine PM.
Dieses mySQLi ist nicht meine erste Wahr gewesen, als es seinerzeit in die WB Classic eingebaut wurde.
Persönlich würde ich es am liebsten so sehen, dass man auch andere Datanbanken verwenden könnte. Denke da im besonderen auch an SQLite.
Aber muss nicht zwangsläufig.
Gruß,
Chris
“We can easily forgive a child who is afraid of the dark; the real tragedy of life is when men are afraid of the light.” ― Plato
Offline
PM an Norhei raus. Ich hab mal fleissig an der Klasse gearbeitet... hier das noch nicht fertige Resultat für die Geeks unter euch:
[== PHP ==]
class Database
{
/**
* PDO driver.
*
* @var string
*/
private $driver = 'mysql';
/**
* Database host.
*
* @var string
*/
private $host = 'localhost';
/**
* Database name.
*
* @var string
*/
private $dbname = '';
/**
* Database username.
*
* @var string
*/
private $username = '';
/**
* Database password.
*
* @var string
*/
private $password = '';
/**
* Database charset.
*
* @var string
*/
private $charset = 'utf8';
/**
* PDO options.
*
* @var array
*/
private $options = array(
PDO::ATTR_CURSOR => PDO::CURSOR_SCROLL,
);
/**
* PDO connection.
*
* @var \PDO
*/
private $pdo;
/**
* Constructor.
*/
public function __construct()
{
if (defined('DB_DRIVER')) {
$this->driver = DB_DRIVER;
}
if (defined('DB_HOST')) {
$this->host = DB_HOST;
if (defined('DB_PORT')) {
$this->host . ':' . DB_PORT;
}
}
if (defined('DB_NAME')) {
$this->dbname = DB_NAME;
} else {
throw new \Exception('Database name (DB_NAME) not defined');
}
if (defined('DB_USERNAME')) {
$this->username = DB_USERNAME;
}
if (defined('DB_PASSWORD')) {
$this->password = DB_PASSWORD;
}
if (defined('DB_CHARSET')) {
$this->charset = preg_replace('/[^a-z0-9]/i', '', DB_CHARSET);
}
$this->connect();
}
/**
* Connect to database.
*
* @return bool
*/
public function connect()
{
$this->pdo = new \PDO($this->driver . ':host=' . $this->host . ';dbname=' . $this->dbname, $this->username, $this->password);
$this->pdo->exec('SET NAMES ' . $this->charset);
$this->pdo->exec('SET @@sql_mode=""');
return true;
}
/**
* Disconnect from database.
*
* @return bool
*/
public function disconnect()
{
$this->pdo = null;
return true;
}
/**
* Execute query.
*
* @param string $query
*
* @return mixed
*/
public function query($query)
{
$statement = $this->pdo->query($query, $this->options);
if ($statement) {
return new \DatabaseResult($statement);
} else {
return;
}
}
/**
* Get the first column of the first row
* @param string $query
* @return mixed
*/
public function get_one($query)
{
$result = $this->query($query);
if ($result) {
$row = $result->fetchRow();
if (isset($row[0])) {
return $row[0];
}
}
return null;
}
/**
* Hass error.
*
* @return string
*/
public function is_error()
{
return ($this->get_error() !== '');
}
/**
* Get error message.
*
* @return string
*/
public function get_error()
{
$errorInfo = $this->statement->errorInfo();
return $errorInfo[2];
}
/**
* Set database options.
*
* @param array $options
*/
public function options(array $options)
{
$this->options = array_merge($this->options, $options);
}
}
class DatabaseResult
{
/**
* PDO statement.
*
* @var \PDOStatement
*/
private $statement;
/**
* PDO fetch style.
*
* @var int
*/
private $fetchStyle = \PDO::FETCH_BOTH;
/**
* Constructor.
*
* @param \PDOStatement $statement
*/
public function __construct(\PDOStatement $statement)
{
$this->statement = $statement;
}
/**
* Fetch number of rows.
*
* @return int
*/
public function numRows()
{
return $this->statement->rowCount();
}
/**
* Rewind fetch cursor.
*
* @return mixed
*/
public function rewind()
{
return $this->seekRow();
}
/**
* Seek for row.
*
* @param int $offset
*
* @return mixed
*/
public function seekRow($offset = 0)
{
$numberOfRows = $this->numRows();
if ($offset >= $numberOfRows) {
$offset = $numberOfRows - 1;
}
return $this->statement->fetch($this->fetchStyle, \PDO::FETCH_ORI_ABS, $offset);
}
/**
* Fetch row.
*
* @param int $fetchStyle
*
* @return mixed
*/
public function fetchRow($fetchStyle = \PDO::FETCH_BOTH)
{
$this->fetchStyle = $fetchStyle;
return $this->statement->fetch($fetchStyle);
}
/**
* Get error message.
*
* @return string
*/
public function error()
{
$errorInfo = $this->statement->errorInfo();
return $errorInfo[2];
}
}
Feierabend für heute. Morgen gehts weiter...
Last edited by rjgamer (21.06.2016 16:11:21)
Offline
Arbeite gerade daran und werde den Beitrag nochmals überarbeiten...
Last edited by rjgamer (22.06.2016 05:50:48)
Offline
Hallo zusammen,
ich hab die class.database.php zu 100% mit PDO neugeschrieben, leicht erweitert und veraltete Methoden- und Properties-Aufrufe als Deprecated markiert.
Die Klassen habe ich in den V1.2.x Branch meines WBCE Forks auf GitHub commited. Einen ausstehenden Pull Request zum Base Fork resp. dem V1.2.x Branch von WBCE habe ich auch erstellt.
Folgende Vorteile bieten die neugeschriebenen Datenbank Klassen gegenüber der bestehend Lösung:
Nutzung von PDO anstatt Mysqli, mit allen seinen Vorteilen
Neuer Config-Parameter DB_DRIVER - somit kann WBCE neu auch andere Datenbanktypen unterstützen
Neue Methode preparedQuery($query, $parameters = array()) um SQL Injection sauber vorzubeugen
Neue Methode getPdo() um die PDO Instanz zu beziehen, damit man alles machen kann, was PDO bietet und die WBCE-eigene Datenbank Klassen nicht können
Bisherige Methoden- und Properties-Aufrufe werden weiterhin unterstützt, sind teilweise aber als Deprecated markiert
Die Datenbank Klassen nutzen den Namespace \Persistence und allfällige Konflikte zu vermeiden
Der Code ist zu 100% von mir geschrieben, somit GPL-konform und darf von WBCE übernommen werden
Sauber dokumentierter und PSR-konformer Code
Ich hab mir erlaubt die Methoden für das Hinzufügen und Entfernen von Indexes zu entfernen, weil ich schlichtweg keinen Aufruf dieser Methoden im Code von WBCE finden konnte und eine Implementierung somit keinen Sinn mehr gemacht hätte.
@Devs - Guckt euch doch bitte meinen Pull Request an. Getestet habe ich es aber noch nicht ordentlich...
Freue mich auf eure Rückmeldung!
Gruss
Last edited by rjgamer (22.06.2016 09:56:17)
Offline
Hallo RJ,
ich finde das interessant. Wenn ich etwas mehr Zeit habe, teste ich es mal.
Was das Setzen von Methoden auf deprecated angeht, ab hier:
https://github.com/rjgamer/WebsiteBaker … e.php#L427
Ich weiß nicht, ob das so gut ist, da dies die Standard-Methoden in sämtlichen Modulen sind.
Ich hab mir erlaubt die Methoden für das Hinzufügen und Entfernen von Indexes zu entfernen, weil ich schlichtweg keinen Aufruf dieser Methoden im Code von WBCE finden konnte und eine Implementierung somit keinen Sinn mehr gemacht hätte.
Welche war das? Kannst Du drauf verlinken?
Gruß,
Chris
P.S. Hast Du NorHei erreicht, hat er zurückgeschrieben?
P.S.2. Wegen dem Grid/Theme melde ich mich bald. Muss noch ein paar Sachen abschließen, bevor ich den Kopf dafür frei habe.
“We can easily forgive a child who is afraid of the dark; the real tragedy of life is when men are afraid of the light.” ― Plato
Offline
Was das Setzen von Methoden auf deprecated angeht, ab hier:
https://github.com/rjgamer/WebsiteBaker … e.php#L427Ich weiß nicht, ob das so gut ist, da dies die Standard-Methoden in sämtlichen Modulen sind.
Eigentlich sind die Methoden, abgesehen von den Properties, nicht deprecated, sondern der Namen der Methode einfach nicht PSR-konform geschrieben. Nichtsdestotrotz, die Deprecated Meldungen werden im produktiven Modus ja nicht ausgegeben. Die Meldungen machen aber durchaus Sinn wenn man an WBCE frickelt und neue Module realisiert, weil man dann im DEBUG Modus aufgefordert wird die neuen Methoden und Properties der Datenbank Klassen zu nutzen.
Ich hab mir erlaubt die Methoden für das Hinzufügen und Entfernen von Indexes zu entfernen, weil ich schlichtweg keinen Aufruf dieser Methoden im Code von WBCE finden konnte und eine Implementierung somit keinen Sinn mehr gemacht hätte.
Welche war das? Kannst Du drauf verlinken?
Die, die und die Methoden haben ich entfernt.
P.S. Hast Du NorHei erreicht, hat er zurückgeschrieben?
Ich hab ihm geschrieben, er hat auch ausführlich zurückgeschrieben aber zZ. gerade nicht viel Zeit.
Freue mich auf erste Tests von euch!
Offline
stefanek wrote:Ich hab mir erlaubt die Methoden für das Hinzufügen und Entfernen von Indexes zu entfernen, weil ich schlichtweg keinen Aufruf dieser Methoden im Code von WBCE finden konnte und eine Implementierung somit keinen Sinn mehr gemacht hätte.
Welche war das? Kannst Du drauf verlinken?
Danke. Diese Methoden sind in der Tat Exoten, die man wohl kaum im Einsatz braucht.
Was ich cool fände, wäre aber eine Methode die ein ganzes Array Update macht.
Hier ist nur eine Funktion dafür:
https://github.com/WBCE/WebsiteBaker_Co … e.php#L457
Ich verwende sie aber nie. Ich habe in meinen Modulen eine eigene Funktion,die das tut.
Doch besser wäre eine Methode.
Meine Funktion verwende ich oft, weil ich es absolut nicht mag, langatmige UPDATE queries zu schreiben mit SET und VALUE. Man verliert den Überblick. Mit einer Funktion übegibt man ein zusammenhängendes Array und gut ist.
Aber wegen der generellen Fragen, da musst Du Dich wohl gedulden, bis NorHei wieder mehr Zeit hat.
Ich weiß dass er da noch eine andere Idee angedacht hat.
Meinst Du, man könnte Deine neuen Klassen dazu bringen SQLite zu schlucken?
Gruß,
Chris
“We can easily forgive a child who is afraid of the dark; the real tragedy of life is when men are afraid of the light.” ― Plato
Offline
Was ich cool fände, wäre aber eine Methode die ein ganzes Array Update macht.
Hier ist nur eine Funktion dafür:
https://github.com/WBCE/WebsiteBaker_Co … e.php#L457
Ich verwende sie aber nie. Ich habe in meinen Modulen eine eigene Funktion,die das tut.
Doch besser wäre eine Methode.Meine Funktion verwende ich oft, weil ich es absolut nicht mag, langatmige UPDATE queries zu schreiben mit SET und VALUE. Man verliert den Überblick. Mit einer Funktion übegibt man ein zusammenhängendes Array und gut ist.
Coole Idee. Werde ich noch implementieren.
Wenn ich Norhei richtig verstanden habe, schwebt ihm der Einsatz eines ORM wie Redbean vor. Aber er selber sagt, dass dies was für WBCE V2.0 oder höher sein wird. Meine Datenbank Klassen fokusieren sich zZ. aber eher auf WBCE V1.2.
Gruss
Offline
Also RJ,
meine simple und total unperfekte Funktion aus der Zeit von vor 4 Jahren (die ich aber immer noch verwende), geht so:
[== PHP ==]
function updateRecordFromArray($aInsertArray = array(), $sTableName = '', $sWhereField = '', $iWhereId = ''){
if (isset($sTableName) && is_array($aInsertArray) && !empty($sWhereField) && !is_null($iWhereId)) {
global $database;
$aCollect = array();
foreach ($aInsertArray as $k => $v) {
$aCollect[] = "`".$k."` = '".$v."', ";
}
$sValues = implode("", $aCollect);
$sValues = substr($sValues, 0, -2);
$sQuery = "UPDATE `%s` SET %s WHERE `%s` = '%d'";
// execute the UPDATE query
if($database->query(sprintf($sQuery, $sTableName, $sValues, $sWhereField, $iWhereId))){
return true;
}else{
return false; //$database->get_error();
}
}
}
$aInsertArray = array(), // das array aus colum-name => value bestehend
$sTableName = '',
$sWhereField = '', // die column, die ich als reference vewende, meistens ein auto increment, unique wert
$iWhereId = '' // die ID zu der obigen Column.
Ich habe jetzt $sWhereField auf intvalue beschränkt gehabt damals. Aber strings wären auch OK.
Wenn ich Norhei richtig verstanden habe, schwebt ihm der Einsatz eines ORM wie Redbean vor. Aber er selber sagt, dass dies was für WBCE V2.0 oder höher sein wird. Meine Datenbank Klassen fokusieren sich zZ. aber eher auf WBCE V1.2.
Ah ja, ich erinnere mich.
Wie sieht es aus? Du hast noch nicht beantwortet, ob man das mit SQLite zum Laufen kriegen könnte.
Das wäre mal ein Feature, das mich dringend interessiert. (Auch wenn seine Umsetzung gerne etwas dauern könnte.)
Gruß,
Chris
“We can easily forgive a child who is afraid of the dark; the real tragedy of life is when men are afraid of the light.” ― Plato
Offline
Für SQLite reicht es leider nicht einfach, in der config.php den DB_DRIVER auf sqllite zu stellen.
Ich hab daher die Datenbank Klasse soweit angepasst, dass du in der config.php einen DSN für PDO mitgeben kannst. Dann wird anstatt DB_HOST, DB_USERNAME, etc. nur der DSN genutzt.
Beispiel:
[== PHP ==]
define('DB_DSN', 'sqlite:/opt/databases/mydb.sq3');
define('TABLE_PREFIX', 'wbce_');
define('WB_DEBUG', true);
define('WB_URL', 'http://localhost');
define('ADMIN_DIRECTORY', 'admin');
require_once(dirname(__FILE__) . '/framework/initialize.php');
Gruss
Last edited by rjgamer (22.06.2016 14:51:02)
Offline
Hey, das wäre echt mal interessant.
Was müßte ich sonst noch machen, dass meine Installation auf sqLite läuft?
Nur rein hypothetisch.
Wenn es sauber läuft, denke ich nicht, dass jemand was dagegen hätte, wenn WBCE alternativ mit sqLite und ohne MySQL läuft.
Vor allem kleine Seiten zu bauen wäre dann mit SQLite im Nu erledigt.
Gruß,
Chris
“We can easily forgive a child who is afraid of the dark; the real tragedy of life is when men are afraid of the light.” ― Plato
Offline
Am besten du testest die Klassen mit SQLite gleich mal. Vielleicht muss man noch einige Mysql-lastige Sachen entfernen bei WBCE, aber theoretisch sollte es funzen
Aber ich sehe gerade, dass meine Klassen noch nicht die alten non-prepared Queries für UPDATE, INSERT und DELETE ordentlich ausführt. Muss da mal noch ran...
Offline
Gut, mach mal in Ruhe.
Ich habe grad auch wenig Zeit, um es mit SQLite zu testen.
Aber die Idee gefällt mir sehr gut, es mal zu können.
Gruß,
Chris
“We can easily forgive a child who is afraid of the dark; the real tragedy of life is when men are afraid of the light.” ― Plato
Offline
Hier meine Lösung auf GitHub um riesige SQL Queries für Updates zu verhindern. Das gleiche folgt morgen auch noch für Inserts.
Offline
Hier meine Lösung auf GitHub um riesige SQL Queries für Updates zu verhindern. Das gleiche folgt morgen auch noch für Inserts.
Cool. Ja, mag ich. Gute Lösung, dass er sich den primary key aus dem Array holt.
Wäre nett, wenn NorHei Deine Lösung in Betracht zieht.
Persönlich mag ich es.
Gruß,
Chris
“We can easily forgive a child who is afraid of the dark; the real tragedy of life is when men are afraid of the light.” ― Plato
Offline
Das Error Handling bei der alten DB Klasse aus WB-Zeiten ist ja mal übelst...
Macht es nicht Sinn vermehrt mit Exceptions zu arbeiten? Ist heute ja State of the art beim entwickeln...
Offline
Bei allen solchen Entscheidungen, muss man (neben dem angestrebten Vorteil) auch den Rattenschwanz berücksichtigen, den so eine Änderung nach sich ziehen könnte.
Welche Konsequenzen hat es auf die bisherigen Module? Wird es ein Fallback geben (Unterstützung für die bisherige Verwendung ) und so weiter.
Wir haben viele Module und einige Modulentwickler, die mit OOP wenig bis nichts am Hut haben (wollen) und persönlich greife ich auch gerne zu prozeduralem Code, grade bei kleinen Modulen, und verwende Klassen nur wenn es sonst zu zu vielen Redundanzen kommen würde (das jetzt bei Modulen).
Bei Dir ist es anders. Du beherrscht OOP sehr gut, deswegen kann es sein, dass viele "alte" Lösungen, die nach wie vor im Core sind, für Dich wenig Sinn ergeben, weil Du weißt, wie man sie viel eleganter Lösen würde.
Ich kann hier aber nur für mich sprechen, ich weiß nicht wirklich, was Norbert für die nahe Zukunft geplant hat für den Core.
Was aber wahrscheinlich niemand will, ist, dass Module, nicht OOP Module die aber ihren Dienst tun, überarbeitet werden müssen.
Am besten bei diesen Dingen direkt mit Norbert sprechen.
Ich kann hier im Moment nur sagen, ob ich persönlich etwas mag oder nicht mag. Das ist aber bezüglich des Cores völlig unverbindlich.
Gruß,
Chris
“We can easily forgive a child who is afraid of the dark; the real tragedy of life is when men are afraid of the light.” ― Plato
Offline
Hi,
joa. Hast da gerade schön meine Gedanken ausgeschrieben. Musste im vorherigen Post halt bisschen rumheulen
Ich möchte helfen den Code von WBCE zu modernisieren (PSR-konform, OOP wo möglich, usw...) und doch aber die Abwärtskompatibilität gewährleisten. Bin gespannt zu erfahren was NorHei über meine Klassen denkt...
Gruss
Offline
“We can easily forgive a child who is afraid of the dark; the real tragedy of life is when men are afraid of the light.” ― Plato
Offline
Ich glaube meine Datenbank Klassen sind sogar WBCE V1.1.x kompatibel. Wer Lust hat das Ganze mal zu testen und darf gerne den aktuellen Code hier im Attachement herunterladen und wie folgt installieren:
- Die Datei framework/database.class.php bei der WBCE Installation sichern
- ZIP herunterladen und entpacken
- Die Datei(ein) in das Verzeichnis framework verschieben und database.class.php überschreiben (wenn bei der Sicherung nicht gleich verschoben)
Der Code der DB Klassen für WBCE v1.1 entspricht fast zu 100% der Lösung für WBCE v1.2. Nur eine Zeile für eine nicht wichtige Deprecated Meldung wurde aus Kompatiblitätsgründen auskommentiert.
Feedback erwünscht...
Ergänzung: Bitte nur auf Testinstallationen testen!
Gruss
Last edited by rjgamer (23.06.2016 13:27:50)
Offline
Es scheint soweit zu funktionieren.
Einzig übel ist, dass mir jede deprecated angezeigt wird, auch wenn ich PHP-Fehlermeldungen auf E_NONE eingestellt habe.
So von null auf nix eine deprecated für jedes get_one() ist...
Es gab bei WBCE nie die PSR-konforme Variante getOne() noch nie. Diese gab es nur bei WBDVE.
Ansonsten aber, also bis auf die Flut an deprecated Meldungen, gefällt mir ganz gut.
Gruß,
Chris
“We can easily forgive a child who is afraid of the dark; the real tragedy of life is when men are afraid of the light.” ― Plato
Offline
Offline
Diese steht in der Version, die ich hier habe, nicht zur Verfügung.
Das ist die WBCE Version: 1.2.0-alpha.4
~Chris
“We can easily forgive a child who is afraid of the dark; the real tragedy of life is when men are afraid of the light.” ― Plato
Offline
Achso, bei 1.2 muss du Debug deaktivieren. Aber eigentlich ist das Zip für WBCE 1.1 gedacht
Offline