mirror of
https://github.com/jbcr/core.git
synced 2026-04-23 08:38:04 +02:00
Move the check for JSON to Doctrine/Version class
This commit is contained in:
@@ -55,14 +55,13 @@ HELP
|
||||
$io->text([$message, '']);
|
||||
|
||||
$platform = $this->doctrineVersion->getPlatform();
|
||||
|
||||
$connection = ! empty($platform['connection_status']) ? sprintf('- <comment>%s</comment>', $platform['connection_status']) : '';
|
||||
|
||||
$tableExists = $this->doctrineVersion->tableContentExists() ? '' : sprintf('- <error>Tables not initialised</error>');
|
||||
$connection = ! empty($platform['connection_status']) ? sprintf(' - <comment>%s</comment>', $platform['connection_status']) : '';
|
||||
$tableExists = $this->doctrineVersion->tableContentExists() ? '' : sprintf(' - <error>Tables not initialised</error>');
|
||||
$withJson = $this->doctrineVersion->hasJson() ? 'with JSON' : 'without JSON';
|
||||
|
||||
$io->listing([
|
||||
sprintf('Install type: <info>%s</info>', Version::installType()),
|
||||
sprintf('Database: <info>%s %s</info> %s %s', $platform['driver_name'], $platform['server_version'], $connection, $tableExists),
|
||||
sprintf('Database: <info>%s %s</info>%s%s <info>(%s)</info>', $platform['driver_name'], $platform['server_version'], $connection, $tableExists, $withJson),
|
||||
sprintf('PHP version: <info>%s</info>', PHP_VERSION),
|
||||
sprintf('Operating System: <info>%s</info> - <comment>%s</comment>', php_uname('s'), php_uname('r')),
|
||||
]);
|
||||
|
||||
@@ -5,60 +5,26 @@ declare(strict_types=1);
|
||||
namespace Bolt\Doctrine;
|
||||
|
||||
use Bolt\Common\Json;
|
||||
use Doctrine\DBAL\Driver\PDOConnection;
|
||||
use Doctrine\DBAL\Platforms\MariaDb1027Platform;
|
||||
use Doctrine\DBAL\Platforms\MySQL57Platform;
|
||||
use Doctrine\DBAL\Platforms\MySQL80Platform;
|
||||
use Doctrine\DBAL\Platforms\SqlitePlatform;
|
||||
use Doctrine\ORM\QueryBuilder;
|
||||
use Doctrine\DBAL\Connection;
|
||||
|
||||
class JsonHelper
|
||||
{
|
||||
/**
|
||||
* We're g̶u̶e̶s̶s̶i̶n̶g̶ doing empirical research on which versions of SQLite
|
||||
* support JSON. So far, tests indicate:
|
||||
* - 3.20.1 - Not OK (Travis PHP 7.2)
|
||||
* - 3.27.2 - OK (Bob's Raspberry Pi, running PHP 7.3.11 on Raspbian)
|
||||
* - 3.28.0 - OK (Travis PHP 7.3)
|
||||
* - 3.29.0 - OK (MacOS Mojave)
|
||||
* - 3.30.1 - OK (MacOS Catalina)
|
||||
*/
|
||||
public const SQLITE_WITH_JSON = '3.27.2';
|
||||
|
||||
/**
|
||||
* Because Mysql 5.6 and Sqlite handle values in JSON differently, we
|
||||
* use this method to check if we can use JSON functions directly.
|
||||
*/
|
||||
public static function useJsonFunction(QueryBuilder $qb): bool
|
||||
{
|
||||
$platform = $qb->getEntityManager()->getConnection()->getDatabasePlatform();
|
||||
|
||||
if ($platform instanceof SqlitePlatform) {
|
||||
return self::checkSqliteVersion($qb);
|
||||
}
|
||||
|
||||
// MySQL80Platform is implicitly included with MySQL57Platform
|
||||
if ($platform instanceof MySQL57Platform || $platform instanceof MariaDb1027Platform) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Prepare a given $where and $slug to be used in a query, depending on
|
||||
* whether or not the current platform supports JSON functions
|
||||
*
|
||||
* For example, wrapJsonFunction('foo', 'bar') gives:
|
||||
*
|
||||
* Sqlite, Mysql 5.6 -> [ 'foo', '["bar"]' ]
|
||||
* Mysql 5.7 -> [ "JSON_EXTRACT(foo, '$[0]')", 'bar' ]
|
||||
* Older SQLite, Mysql 5.6 -> [ 'foo', '["bar"]' ]
|
||||
* Newer SQLite, Mysql 5.7 -> [ "JSON_EXTRACT(foo, '$[0]')", 'bar' ]
|
||||
*
|
||||
* @return string|array
|
||||
*/
|
||||
public static function wrapJsonFunction(?string $where = null, ?string $slug = null, QueryBuilder $qb)
|
||||
public static function wrapJsonFunction(?string $where = null, ?string $slug = null, Connection $connection)
|
||||
{
|
||||
if (self::useJsonFunction($qb)) {
|
||||
$version = new Version($connection);
|
||||
|
||||
if ($version->hasJson()) {
|
||||
$resultWhere = 'JSON_EXTRACT(' . $where . ", '$[0]')";
|
||||
$resultSlug = $slug;
|
||||
} else {
|
||||
@@ -76,19 +42,4 @@ class JsonHelper
|
||||
|
||||
return [$resultWhere, $resultSlug];
|
||||
}
|
||||
|
||||
private static function checkSqliteVersion(QueryBuilder $qb): bool
|
||||
{
|
||||
/** @var PDOConnection $wrapped */
|
||||
$wrapped = $qb->getEntityManager()->getConnection()->getWrappedConnection();
|
||||
|
||||
// If the wrapper doesn't have `getAttribute`, we bail…
|
||||
if (! method_exists($wrapped, 'getAttribute')) {
|
||||
return false;
|
||||
}
|
||||
|
||||
[$client_version] = explode(' - ', $wrapped->getAttribute(\PDO::ATTR_CLIENT_VERSION));
|
||||
|
||||
return version_compare($client_version, self::SQLITE_WITH_JSON) > 0;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,9 +7,25 @@ namespace Bolt\Doctrine;
|
||||
use Bolt\Common\Str;
|
||||
use Doctrine\DBAL\Connection;
|
||||
use Doctrine\DBAL\Driver\PDOConnection;
|
||||
use Doctrine\DBAL\Platforms\MariaDb1027Platform;
|
||||
use Doctrine\DBAL\Platforms\MySQL57Platform;
|
||||
use Doctrine\DBAL\Platforms\SqlitePlatform;
|
||||
|
||||
class Version
|
||||
{
|
||||
/**
|
||||
* We're g̶u̶e̶s̶s̶i̶n̶g̶ doing empirical research on which versions of SQLite
|
||||
* support JSON. So far, tests indicate:
|
||||
* - 3.20.1 - Not OK (Travis PHP 7.2)
|
||||
* - 3.27.2 - OK (Bob's Raspberry Pi, running PHP 7.3.11 on Raspbian)
|
||||
* - 3.28.0 - OK (Travis PHP 7.3)
|
||||
* - 3.28.0 - Not OK (Bob's PHP 7.2, installed with Brew)
|
||||
* - 3.29.0 - OK (MacOS Mojave)
|
||||
* - 3.30.1 - OK (MacOS Catalina)
|
||||
*/
|
||||
public const SQLITE_WITH_JSON = '3.27.0';
|
||||
public const PHP_WITH_SQLITE = '7.3.0';
|
||||
|
||||
/** @var Connection */
|
||||
private $connection;
|
||||
|
||||
@@ -53,4 +69,31 @@ class Version
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public function hasJson(): bool
|
||||
{
|
||||
$platform = $this->connection->getDatabasePlatform();
|
||||
|
||||
if ($platform instanceof SqlitePlatform) {
|
||||
return $this->checkSqliteVersion();
|
||||
}
|
||||
|
||||
// MySQL80Platform is implicitly included with MySQL57Platform
|
||||
if ($platform instanceof MySQL57Platform || $platform instanceof MariaDb1027Platform) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private function checkSqliteVersion(): bool
|
||||
{
|
||||
/** @var PDOConnection $wrapped */
|
||||
$wrapped = $this->connection->getWrappedConnection();
|
||||
|
||||
[$client_version] = explode(' - ', $wrapped->getAttribute(\PDO::ATTR_CLIENT_VERSION));
|
||||
|
||||
return (version_compare($client_version, self::SQLITE_WITH_JSON) > 0) &&
|
||||
(version_compare(PHP_VERSION, self::PHP_WITH_SQLITE) > 0);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -127,8 +127,9 @@ class ContentRepository extends ServiceEntityRepository
|
||||
public function findOneBySlug(string $slug, ?ContentType $contentType = null): ?Content
|
||||
{
|
||||
$qb = $this->getQueryBuilder();
|
||||
$connection = $qb->getEntityManager()->getConnection();
|
||||
|
||||
[$where, $slug] = JsonHelper::wrapJsonFunction('translations.value', $slug, $qb);
|
||||
[$where, $slug] = JsonHelper::wrapJsonFunction('translations.value', $slug, $connection);
|
||||
|
||||
$query = $qb
|
||||
->innerJoin('content.fields', 'field')
|
||||
@@ -155,8 +156,9 @@ class ContentRepository extends ServiceEntityRepository
|
||||
public function findOneByFieldValue(string $fieldName, string $value, ?ContentType $contentType = null): ?Content
|
||||
{
|
||||
$qb = $this->getQueryBuilder();
|
||||
$connection = $qb->getEntityManager()->getConnection();
|
||||
|
||||
[$where, $value] = JsonHelper::wrapJsonFunction('translation.value', $value, $qb);
|
||||
[$where, $value] = JsonHelper::wrapJsonFunction('translation.value', $value, $connection);
|
||||
|
||||
$query = $qb
|
||||
->innerJoin('content.fields', 'field')
|
||||
|
||||
@@ -32,8 +32,9 @@ class FieldRepository extends ServiceEntityRepository
|
||||
public function findOneBySlug(string $slug): ?Field
|
||||
{
|
||||
$qb = $this->getQueryBuilder();
|
||||
$connection = $qb->getEntityManager()->getConnection();
|
||||
|
||||
[$where, $slug] = JsonHelper::wrapJsonFunction('translations.value', $slug, $qb);
|
||||
[$where, $slug] = JsonHelper::wrapJsonFunction('translations.value', $slug, $connection);
|
||||
|
||||
return $qb
|
||||
->innerJoin('field.translations', 'translations')
|
||||
|
||||
@@ -352,7 +352,7 @@ class SelectQuery implements QueryInterface
|
||||
|
||||
$originalLeftExpression = 'content.' . $key;
|
||||
|
||||
$newLeftExpression = JsonHelper::wrapJsonFunction($translationsAlias . '.value', null, $this->qb);
|
||||
$newLeftExpression = JsonHelper::wrapJsonFunction($translationsAlias . '.value', null, $em->getConnection());
|
||||
|
||||
$where = $filter->getExpression();
|
||||
$where = str_replace($originalLeftExpression, $newLeftExpression, $where);
|
||||
@@ -377,7 +377,7 @@ class SelectQuery implements QueryInterface
|
||||
->andWhere($this->qb->expr()->in('content.id', $innerQuery->getDQL()));
|
||||
|
||||
foreach ($filter->getParameters() as $key => $value) {
|
||||
$value = JsonHelper::wrapJsonFunction(null, $value, $this->qb);
|
||||
$value = JsonHelper::wrapJsonFunction(null, $value, $em->getConnection());
|
||||
$this->qb->setParameter($key, $value);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user