<?php
/**
* AbstractDatabaseLogger file
*
* Copyright (c) 2016, Kiril Savchev
* All rights reserved.
*
* @category Libs
* @package Logger
*
* @author Kiril Savchev <k.savchev@gmail.com>
*
* @license https://opensource.org/licenses/BSD-3-Clause BSD 3 License
* @link http://ifthenelse.info
*/
namespace Ite\Logger;
use Psr\Log\AbstractLogger;
/**
* AbstractDatabaseLogger
*
* Base database logger class that creates an INSERT SQL query with the log
* parts (message, level, context, etc...) and send them to ancestor's
* write() method for the actual inserting into database. The ancestors must
* implement the write() method on their own way with the prefered DB library.
*
* @version 1.0
*
* @author Kiril Savchev <k.savchev@gmail.com>
*/
abstract class AbstractDatabaseLogger extends AbstractLogger {
use MessagePrepareTrait;
/**
* The default log table
*
* @var string
*/
protected $defaultTable = 'logs';
/**
* The default 'message' field of the table
*
* @var string
*/
protected $messageField = 'message';
/**
* The default date field of the table
*
* @var string
*/
protected $dateField = 'date';
/**
* The default context field of the table
*
* @var string
*/
protected $contextField = 'context';
/**
* The default 'level' field of the table
*
* @var string
*/
protected $levelField = 'level';
/**
* Default preparing behaviour
*
* @var boolean
*/
protected $usePrepare = true;
/**
* Level tables config array
*
* @example 'level' => [
* 'table' => 'tableName',
* 'prepared' => true,
* 'messageField' => 'message',
* 'dateField' => 'date',
* 'contextField' => 'context',
* 'dateField' => 'date',
* 'levelField' => 'level' // or NULL if separate level tables are used
* ]
*
* @var array
*/
protected $tableConfigs = [];
/**
* Default query template with placeholders for table fields and values
*
* @var string
*/
protected $sqlTpl = "INSERT INTO %s(%s,%s,%s,%s) VALUES(%s, %s, %s, NOW())";
/**
* Creates database logger
*
* If config parameter is string it will be used as a default table name,
* otherwise it will be used as a table config and the second parameter
* will be used for default table name.
*
* @param array|string $config [Optional] Table config or default table
* @param string $defaultTable [Optional] The default log table name
*/
public function __construct($config = null, $defaultTable = '') {
if (is_array($config) && $config) {
$this->tableConfigs = $config;
if ($defaultTable) {
$this->defaultTable = $defaultTable;
}
}
else if (is_string($config) && $config) {
$this->defaultTable = $config;
}
}
/**
* Prepares level table config
*
* If some parameter is missing, then the default one is used
*
* @param string $level
* @return array
*/
protected function prepareTableConfig($level) {
if (!array_key_exists($level, $this->tableConfigs)) {
$this->tableConfigs[$level] = [];
}
if (!array_key_exists('table', $this->tableConfigs[$level])) {
$this->tableConfigs[$level]['table'] = $this->defaultTable;
}
if (!array_key_exists('prepared', $this->tableConfigs[$level])) {
$this->tableConfigs[$level]['prepared'] = $this->usePrepare;
}
if (!array_key_exists('messageField', $this->tableConfigs[$level])) {
$this->tableConfigs[$level]['messageField'] = $this->messageField;
}
if (!array_key_exists('contextField', $this->tableConfigs[$level])) {
$this->tableConfigs[$level]['contextField'] = $this->contextField;
}
if (!array_key_exists('levelField', $this->tableConfigs[$level])) {
$this->tableConfigs[$level]['levelField'] = $this->levelField;
}
if (!array_key_exists('dateField', $this->tableConfigs[$level])) {
$this->tableConfigs[$level]['dateField'] = $this->dateField;
}
return $this->tableConfigs[$level];
}
/**
* Prepares the sql query and parameters to write message
*
* If 'prepared' parameter is set to true then the query will has a '?'
* placeholders for the values and the 'params' will holds the values.
* Otherwise the query will contains the values and the 'params' key
* will be empty.
*
* @param string $level The log level
* @param string $message The log message
* @param array $context The log context
* @return array Array with 'query' key for the SQL query and 'params' for the values if the query will be prepared before execute
*/
protected function prepareSQL($level, $message, array $context) {
$tableConfig = $this->prepareTableConfig($level);
$args = [$tableConfig['table'], $tableConfig['messageField'], $tableConfig['contextField'], $tableConfig['levelField'], $tableConfig['dateField']];
if ($tableConfig['prepared']) {
$args = array_merge($args, ["?", "?", "?"]);
$params = [$message, $this->prepareContext($context), $level];
}
else {
$args = array_merge($args, ["'{$message}'", "'".$this->prepareContext($context)."'", "'{$level}'"]);
$params = [];
}
$sql = vsprintf($this->sqlTpl, $args);
return ['query' => $sql, 'params' => $params];
}
/**
* Trigger the database logging
*
* This method will craete the INSERT SQL statement and will provide it
* and array with parameters if any, to the abstract write() method to
* insert the log into database table
*
* @param string $level The log level
* @param string $message The log message
* @param array $context The log context
*/
public function log($level, $message, array $context = []) {
$sql = $this->prepareSQL($level, $message, $context);
$this->write($sql['query'], $sql['params'], $this->tableConfigs[$level]['prepared']);
}
/**
* The actual writing to the database
*
* Every ancestor of this class must implement on their own the way of
* database query with the prefered library (e.g. \mysqli, \PDO, etc...)
*
* @param string $sql The INSERT SQL query
* @param array $params [Optional] Parameters if the query will be prepared before executing
* @param bool $mustPrepare [Optional] Whether or not to prepare the statement. Default false
*/
abstract protected function write($sql, array $params = [], $mustPrepare = false);
/**
* Get the default table name
*
* @return string
*/
public function getDefaultTable() {
return $this->defaultTable;
}
/**
* Get the default 'message' field
*
* @return string
*/
public function getMessageField() {
return $this->messageField;
}
/**
* Get the default 'date' field
*
* @return string
*/
public function getDateField() {
return $this->dateField;
}
/**
* Get the default 'context' field
*
* @return string
*/
public function getContextField() {
return $this->contextField;
}
/**
* Get the default 'level' field
*
* @return string
*/
public function getLevelField() {
return $this->levelField;
}
public function getUsePrepare() {
return $this->usePrepare;
}
/**
* Get the table configs
*
* @return array
*/
public function getTableConfigs() {
return $this->tableConfigs;
}
/**
* Sets the default table name
*
* @param string $defaultTable
* @return \Ite\Logger\AbstractDatabaseLogger
*/
public function setDefaultTable($defaultTable) {
$this->defaultTable = $defaultTable;
return $this;
}
/**
* Sets the default message field
*
* @param string $messageField
* @return \Ite\Logger\AbstractDatabaseLogger
*/
public function setMessageField($messageField) {
$this->messageField = $messageField;
return $this;
}
/**
* Sets the default date field
*
* @param string $dateField
* @return \Ite\Logger\AbstractDatabaseLogger
*/
public function setDateField($dateField) {
$this->dateField = $dateField;
return $this;
}
/**
* Sets the default context field
*
* @param string $contextField
* @return \Ite\Logger\AbstractDatabaseLogger
*/
public function setContextField($contextField) {
$this->contextField = $contextField;
return $this;
}
/**
* Sets the default level field
*
* @param string $levelField
* @return \Ite\Logger\AbstractDatabaseLogger
*/
public function setLevelField($levelField) {
$this->levelField = $levelField;
return $this;
}
/**
* Sets whether or not to prepare the statement
*
* @param bool $usePrepare
* @return \Ite\Logger\AbstractDatabaseLogger
*/
public function setUsePrepare($usePrepare) {
$this->usePrepare = $usePrepare;
return $this;
}
/**
* Sets the table configs
*
* @param array $tableConfigs
* @return \Ite\Logger\AbstractDatabaseLogger
*/
public function setTableConfigs(array $tableConfigs) {
$this->tableConfigs = $tableConfigs;
return $this;
}
/**
* Get default query template
* @return string
*/
public function getSqlTpl() {
return $this->sqlTpl;
}
/**
* Sets default query template
*
* @param string $sqlTpl
* @return \Ite\Logger\AbstractDatabaseLogger
*/
public function setSqlTpl($sqlTpl) {
$this->sqlTpl = $sqlTpl;
return $this;
}
}
|