diff --git a/CHANGELOG.md b/CHANGELOG.md index 6aa9eedb..0d9d1320 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,20 @@ +3.1.4 + +- improved DBALDataSource to work with custom types (thanks villermen) + +3.1.3 + +- updated LaravelCacheDataSource to support Laravel 5.8 + +3.1.2 + +- fixed missing use statement in vanilla integration (thanks micc83) + +3.1.1 + +- exposed the Request::setAuthenticatedUser method on the main Clockwork class +- fixed possible crash in LaravelDataSource when resolving authenticated user in non-standard auth implementations (thanks freshleafmedia, motia) + 3.1 - added new integration for vanilla PHP (thanks martbean) diff --git a/Clockwork/Clockwork.php b/Clockwork/Clockwork.php index 868d03a7..402ef27f 100644 --- a/Clockwork/Clockwork.php +++ b/Clockwork/Clockwork.php @@ -19,7 +19,7 @@ class Clockwork implements LoggerInterface /** * Clockwork version */ - const VERSION = '3.1'; + const VERSION = '3.1.4'; /** * Array of data sources, these objects provide data to be stored in a request object @@ -342,6 +342,12 @@ public function subrequest($url, $id, $path = null) return $this->getRequest()->addSubrequest($url, $id, $path); } + // Set the authenticated user, takes the username, id and additional data - email and full name of the user + public function setAuthenticatedUser($username, $id = null, $data = []) + { + return $this->getRequest()->setAuthenticatedUser($username, $id, $data); + } + // Add custom user data (presented as additional tabs in the official app) public function userData($key = null) { diff --git a/Clockwork/DataSource/DBALDataSource.php b/Clockwork/DataSource/DBALDataSource.php index 8ccf870f..d6cb5824 100644 --- a/Clockwork/DataSource/DBALDataSource.php +++ b/Clockwork/DataSource/DBALDataSource.php @@ -5,7 +5,8 @@ use Doctrine\DBAL\Logging\SQLLogger; use Doctrine\DBAL\Logging\LoggerChain; -use Doctrine\ORM\EntityManager; +use Doctrine\DBAL\Platforms\AbstractPlatform; +use Doctrine\DBAL\Types\Type; use Doctrine\DBAL\Connection; class DBALDataSource extends DataSource implements SQLLogger @@ -68,7 +69,7 @@ public function startQuery($sql, array $params = null, array $types = null) { $this->start = microtime(true); - $sql = $this->replaceParams($sql, $params); + $sql = $this->replaceParams($this->connection->getDatabasePlatform(), $sql, $params, $types); $sql = $this->formatQuery($sql); $this->query = [ 'sql' => $sql, 'params' => $params, 'types' => $types ]; @@ -91,43 +92,87 @@ protected function formatQuery($sql) }, $sql); } - protected function replaceParams($sql, $params) + /** + * Source at laravel-doctrine/orm LaravelDoctrine\ORM\Loggers\Formatters\ReplaceQueryParams::format(). + * + * @param AbstractPlatform $platform + * @param string $sql + * @param array|null $params + * @param array|null $types + * + * + * @return string + */ + public function replaceParams($platform, $sql, array $params = null, array $types = null) { if (is_array($params)) { - foreach ($params as $param) { - $param = $this->convertParam($param); + foreach ($params as $key => $param) { + $type = isset($types[$key]) ? $types[$key] : null; // Originally used null coalescing + $param = $this->convertParam($platform, $param, $type); $sql = preg_replace('/\?/', "$param", $sql, 1); } } - return $sql; } - protected function convertParam($param) + /** + * Source at laravel-doctrine/orm LaravelDoctrine\ORM\Loggers\Formatters\ReplaceQueryParams::convertParam(). + * + * @param mixed $param + * + * @throws \Exception + * @return string + */ + protected function convertParam($platform, $param, $type = null) { if (is_object($param)) { - if (! method_exists($param, '__toString')) { - if ($param instanceof \DateTime || $param instanceof \DateTimeImmutable) { + if (!method_exists($param, '__toString')) { + if ($param instanceof \DateTimeInterface) { $param = $param->format('Y-m-d H:i:s'); + } elseif (Type::hasType($type)) { + $type = Type::getType($type); + $param = $type->convertToDatabaseValue($param, $platform); } else { throw new \Exception('Given query param is an instance of ' . get_class($param) . ' and could not be converted to a string'); } } } elseif (is_array($param)) { - if (count($param) !== count($param, COUNT_RECURSIVE)) { + if ($this->isNestedArray($param)) { $param = json_encode($param, JSON_UNESCAPED_UNICODE); } else { - $param = implode(', ', array_map(function ($part) { - return '"' . (string) $part . '"'; - }, $param)); - + $param = implode( + ', ', + array_map( + function ($part) { + return '"' . (string) $part . '"'; + }, + $param + ) + ); return '(' . $param . ')'; } + } else { + $param = htmlspecialchars($param); // Originally used the e() Laravel helper } - return '"' . (string) $param . '"'; } + /** + * Source at laravel-doctrine/orm LaravelDoctrine\ORM\Loggers\Formatters\ReplaceQueryParams::isNestedArray(). + * + * @param array $array + * @return bool + */ + private function isNestedArray(array $array) + { + foreach ($array as $key => $value) { + if (is_array($value)) { + return true; + } + } + return false; + } + /** * From SQLLogger Doctrine Interface */ diff --git a/Clockwork/DataSource/LaravelCacheDataSource.php b/Clockwork/DataSource/LaravelCacheDataSource.php index d7f4d69f..0f52c508 100644 --- a/Clockwork/DataSource/LaravelCacheDataSource.php +++ b/Clockwork/DataSource/LaravelCacheDataSource.php @@ -62,7 +62,8 @@ public function listenToEvents() }); $this->eventDispatcher->listen(\Illuminate\Cache\Events\KeyWritten::class, function ($event) { $this->registerQuery([ - 'type' => 'write', 'key' => $event->key, 'value' => $event->value, 'expiration' => $event->minutes * 60 + 'type' => 'write', 'key' => $event->key, 'value' => $event->value, + 'expiration' => property_exists($event, 'seconds') ? $event->seconds : $event->minutes * 60 ]); }); $this->eventDispatcher->listen(\Illuminate\Cache\Events\KeyForgotten::class, function ($event) { diff --git a/Clockwork/DataSource/LaravelDataSource.php b/Clockwork/DataSource/LaravelDataSource.php index 90cf733d..9ccd5cd6 100644 --- a/Clockwork/DataSource/LaravelDataSource.php +++ b/Clockwork/DataSource/LaravelDataSource.php @@ -255,7 +255,7 @@ protected function getSessionData() if (! isset($this->app['session'])) { return []; } - + return $this->removePasswords((new Serializer)->normalizeEach($this->app['session']->all())); } @@ -263,10 +263,11 @@ protected function getSessionData() protected function resolveAuthenticatedUser(Request $request) { if (! ($user = $this->app['auth']->user())) return; + if (! isset($user->email) || ! isset($user->id)) return; $request->setAuthenticatedUser($user->email, $user->id, [ - 'email' => $user->email, - 'name' => $user->name + 'email' => isset($user->email) ? $user->email : null, + 'name' => isset($user->name) ? $user->name : null ]); } } diff --git a/Clockwork/Request/Request.php b/Clockwork/Request/Request.php index c8c9b377..9137a960 100644 --- a/Clockwork/Request/Request.php +++ b/Clockwork/Request/Request.php @@ -341,6 +341,7 @@ public function addSubrequest($url, $id, $data = []) ]; } + // Set the authenticated user, takes the username, id and additional data - email and full name of the user public function setAuthenticatedUser($username, $id = null, $data = []) { $this->authenticatedUser = [