Subversion-Projekte lars-tiefland.laravel_shop

Revision

Details | Letzte Änderung | Log anzeigen | RSS feed

Revision Autor Zeilennr. Zeile
199 lars 1
<?php namespace Clockwork\DataSource;
2
 
3
use Clockwork\Request\Request;
4
 
5
use Doctrine\DBAL\Connection;
6
use Doctrine\DBAL\Logging\LoggerChain;
7
use Doctrine\DBAL\Logging\SQLLogger;
8
use Doctrine\DBAL\Platforms\AbstractPlatform;
9
use Doctrine\DBAL\Types\Type;
10
 
11
// Data source for DBAL, provides database queries
12
class DBALDataSource extends DataSource implements SQLLogger
13
{
14
	// Array of collected queries
15
	protected $queries = [];
16
 
17
	// Current running query
18
	protected $query = null;
19
 
20
	// DBAL connection
21
	protected $connection;
22
 
23
	// DBAL connection name
24
	protected $connectionName;
25
 
26
	// Create a new data source instance, takes a DBAL connection instance as an argument
27
	public function __construct(Connection $connection)
28
	{
29
		$this->connection = $connection;
30
		$this->connectionName = $this->connection->getDatabase();
31
 
32
		$configuration = $this->connection->getConfiguration();
33
		$currentLogger = $configuration->getSQLLogger();
34
 
35
		if ($currentLogger === null) {
36
			$configuration->setSQLLogger($this);
37
		} else {
38
			$loggerChain = new LoggerChain;
39
			$loggerChain->addLogger($currentLogger);
40
			$loggerChain->addLogger($this);
41
 
42
			$configuration->setSQLLogger($loggerChain);
43
		}
44
	}
45
 
46
	// Adds executed database queries to the request
47
	public function resolve(Request $request)
48
	{
49
		$request->databaseQueries = array_merge($request->databaseQueries, $this->queries);
50
 
51
		return $request;
52
	}
53
 
54
	// Reset the data source to an empty state, clearing any collected data
55
	public function reset()
56
	{
57
		$this->queries = [];
58
		$this->query = null;
59
	}
60
 
61
	// DBAL SQLLogger event
62
	public function startQuery($sql, array $params = null, array $types = null)
63
	{
64
		$this->query = [
65
			'query'  => $sql,
66
			'params' => $params,
67
			'types'  => $types,
68
			'time'   => microtime(true)
69
		];
70
	}
71
 
72
	// DBAL SQLLogger event
73
	public function stopQuery()
74
	{
75
		$this->registerQuery($this->query);
76
		$this->query = null;
77
	}
78
 
79
	// Collect an executed database query
80
	protected function registerQuery($query)
81
	{
82
		$query = [
83
			'query'      => $this->createRunnableQuery($query['query'], $query['params'], $query['types']),
84
			'bindings'   => $query['params'],
85
			'duration'   => (microtime(true) - $query['time']) * 1000,
86
			'connection' => $this->connectionName,
87
			'time'       => $query['time']
88
		];
89
 
90
		if ($this->passesFilters([ $query ])) {
91
			$this->queries[] = $query;
92
		}
93
	}
94
 
95
	// Takes a query, an array of params and types as arguments, returns runnable query with upper-cased keywords
96
	protected function createRunnableQuery($query, $params, $types)
97
	{
98
		// add params to query
99
		$query = $this->replaceParams($this->connection->getDatabasePlatform(), $query, $params, $types);
100
 
101
		// highlight keywords
102
		$keywords = [
103
			'select', 'insert', 'update', 'delete', 'into', 'values', 'set', 'where', 'from', 'limit', 'is', 'null',
104
			'having', 'group by', 'order by', 'asc', 'desc'
105
		];
106
		$regexp = '/\b' . implode('\b|\b', $keywords) . '\b/i';
107
 
108
		return preg_replace_callback($regexp, function ($match) { return strtoupper($match[0]); }, $query);
109
	}
110
 
111
	/**
112
	 * Source at laravel-doctrine/orm LaravelDoctrine\ORM\Loggers\Formatters\ReplaceQueryParams::format().
113
	 *
114
	 * @param AbstractPlatform $platform
115
	 * @param string           $sql
116
	 * @param array|null       $params
117
	 * @param array|null       $types
118
	 *
119
	 *
120
	 * @return string
121
	 */
122
	public function replaceParams($platform, $sql, array $params = null, array $types = null)
123
	{
124
		if (is_array($params)) {
125
			foreach ($params as $key => $param) {
126
				$type  = isset($types[$key]) ? $types[$key] : null; // Originally used null coalescing
127
				$param = $this->convertParam($platform, $param, $type);
128
				$sql   = preg_replace('/\?/', "$param", $sql, 1);
129
			}
130
		}
131
		return $sql;
132
	}
133
 
134
	/**
135
	 * Source at laravel-doctrine/orm LaravelDoctrine\ORM\Loggers\Formatters\ReplaceQueryParams::convertParam().
136
	 *
137
	 * @param mixed $param
138
	 *
139
	 * @throws \Exception
140
	 * @return string
141
	 */
142
	protected function convertParam($platform, $param, $type = null)
143
	{
144
		if (is_object($param)) {
145
			if (!method_exists($param, '__toString')) {
146
				if ($param instanceof \DateTimeInterface) {
147
					$param = $param->format('Y-m-d H:i:s');
148
				} elseif (Type::hasType($type)) {
149
					$type  = Type::getType($type);
150
					$param = $type->convertToDatabaseValue($param, $platform);
151
				} else {
152
					throw new \Exception('Given query param is an instance of ' . get_class($param) . ' and could not be converted to a string');
153
				}
154
			}
155
		} elseif (is_array($param)) {
156
			if ($this->isNestedArray($param)) {
157
				$param = json_encode($param, JSON_UNESCAPED_UNICODE);
158
			} else {
159
				$param = implode(
160
					', ',
161
					array_map(
162
						function ($part) {
163
							return '"' . (string) $part . '"';
164
						},
165
						$param
166
					)
167
				);
168
				return '(' . $param . ')';
169
			}
170
		} else {
171
			$param = htmlspecialchars((string) $param); // Originally used the e() Laravel helper
172
		}
173
		return '"' . (string) $param . '"';
174
	}
175
 
176
	/**
177
	 * Source at laravel-doctrine/orm LaravelDoctrine\ORM\Loggers\Formatters\ReplaceQueryParams::isNestedArray().
178
	 *
179
	 * @param  array $array
180
	 * @return bool
181
	 */
182
	private function isNestedArray(array $array)
183
	{
184
		foreach ($array as $key => $value) {
185
			if (is_array($value)) {
186
				return true;
187
			}
188
		}
189
		return false;
190
	}
191
}