close(); } /** * Setup db connection. * Based on defined options, this method connects to db defined in {@link $dsn} * and creates a {@link $table} table if {@link $createTable} is true. * @return boolean true if all ok. * @throws a PDOException if the attempt to connect to the requested database fails. */ public function activateOptions() { try { if($this->user === null) { $this->db = new PDO($this->dsn); } else if($this->password === null) { $this->db = new PDO($this->dsn, $this->user); } else { $this->db = new PDO($this->dsn,$this->user,$this->password); } $this->db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); // test if log table exists try { $result = $this->db->query('SELECT * FROM ' . $this->table . ' WHERE 1 = 0'); $result->closeCursor(); } catch (PDOException $e) { // It could be something else but a "no such table" is the most likely $result = false; } // create table if necessary if ($result == false and $this->createTable) { // The syntax should at least be compatible with MySQL, PostgreSQL, SQLite and Oracle. $query = "CREATE TABLE {$this->table} (". "timestamp varchar(32)," . "logger varchar(64)," . "level varchar(32)," . "message varchar(9999)," . "thread varchar(32)," . "file varchar(255)," . "line varchar(6))"; $result = $this->db->query($query); } } catch (PDOException $e) { $this->canAppend = false; throw new LoggerException($e); } $this->layout = new LoggerLayoutPattern(); // // Keep compatibility to legacy option $sql which already included the format patterns! // if (empty($this->sql)) { // new style with prepared Statment and $insertSql and $insertPattern // Maybe the tablename has to be substituted. $this->insertSql = preg_replace('/__TABLE__/', $this->table, $this->insertSql); $this->preparedInsert = $this->db->prepare($this->insertSql); $this->layout->setConversionPattern($this->insertPattern); } else { // Old style with format strings in the $sql query should be used. $this->layout->setConversionPattern($this->sql); } $this->canAppend = true; return true; } /** * Appends a new event to the database. * * @throws LoggerException If the pattern conversion or the INSERT statement fails. */ public function append(LoggerLoggingEvent $event) { // TODO: Can't activateOptions() simply throw an Exception if it encounters problems? if ( ! $this->canAppend) return; try { if (empty($this->sql)) { // new style with prepared statement $params = $this->layout->formatToArray($event); $this->preparedInsert->execute($params); } else { // old style $query = $this->layout->format($event); $this->db->exec($query); } } catch (Exception $e) { throw new LoggerException($e); } } /** * Closes the connection to the logging database */ public function close() { if($this->closed != true) { if ($this->db !== null) { $this->db = null; } $this->closed = true; } } /** * Sets the username for this connection. * Defaults to '' */ public function setUser($user) { $this->user = $user; } /** * Sets the password for this connection. * Defaults to '' */ public function setPassword($password) { $this->password = $password; } /** * Indicator if the logging table should be created on startup, * if its not existing. */ public function setCreateTable($flag) { $this->createTable = LoggerOptionConverter::toBoolean($flag, true); } /** * Sets the SQL string into which the event should be transformed. * Defaults to: * * INSERT INTO $this->table * ( timestamp, logger, level, message, thread, file, line) * VALUES * ('%d','%c','%p','%m','%t','%F','%L') * * It's not necessary to change this except you have customized logging' * * @deprecated See {@link setInsertSql} and {@link setInsertPattern}. */ public function setSql($sql) { $this->sql = $sql; } /** * Sets the SQL INSERT string to use with {@link $insertPattern}. * * @param $sql A complete INSERT INTO query with "?" that gets replaced. */ public function setInsertSql($sql) { $this->insertSql = $sql; } /** * Sets the {@link LoggerLayoutPattern} format strings for {@link $insertSql}. * * It's not necessary to change this except you have customized logging. * * @param $pattern Comma separated format strings like "%p,%m,%C" */ public function setInsertPattern($pattern) { $this->insertPattern = $pattern; } /** * Sets the tablename to which this appender should log. * Defaults to log4php_log */ public function setTable($table) { $this->table = $table; } /** * Sets the DSN string for this connection. In case of * SQLite it could look like this: 'sqlite:appenders/pdotest.sqlite' */ public function setDSN($dsn) { $this->dsn = $dsn; } /** * Sometimes databases allow only one connection to themselves in one thread. * SQLite has this behaviour. In that case this handle is needed if the database * must be checked for events. * * @return PDO */ public function getDatabaseHandle() { return $this->db; } }