From 6b700c725b6121767fca24f33f62a1bdad4f1483 Mon Sep 17 00:00:00 2001 From: Wytse Talsma Date: Tue, 29 Sep 2020 13:54:54 +0200 Subject: [PATCH 01/23] Freebsd-Installable --- .../src/Analysers/PlatformAnalyser.php | 58 +++++++++++++++++++ .../Interfaces/PlatformAnalyserInterface.php | 27 +++++++++ 2 files changed, 85 insertions(+) create mode 100644 vendor/vaimo/webdriver-binary-downloader/src/Analysers/PlatformAnalyser.php create mode 100644 vendor/vaimo/webdriver-binary-downloader/src/Interfaces/PlatformAnalyserInterface.php diff --git a/vendor/vaimo/webdriver-binary-downloader/src/Analysers/PlatformAnalyser.php b/vendor/vaimo/webdriver-binary-downloader/src/Analysers/PlatformAnalyser.php new file mode 100644 index 000000000..02a8c6904 --- /dev/null +++ b/vendor/vaimo/webdriver-binary-downloader/src/Analysers/PlatformAnalyser.php @@ -0,0 +1,58 @@ + 'Linux 32Bits', + self::TYPE_LINUX64 => 'Linux 64Bits', + self::TYPE_MAC64 => 'Mac OS X', + self::TYPE_WIN32 => 'Windows 32Bits', + self::TYPE_WIN64 => 'Windows 64Bits', + self::TYPE_FREEBSD64 => 'FreeBSD 64Bits', + self::TYPE_FREEBSD32 => 'FreeBSD 32Bits', + ); + + return $names[$this->getPlatformCode()]; + } +} diff --git a/vendor/vaimo/webdriver-binary-downloader/src/Interfaces/PlatformAnalyserInterface.php b/vendor/vaimo/webdriver-binary-downloader/src/Interfaces/PlatformAnalyserInterface.php new file mode 100644 index 000000000..b22944cd1 --- /dev/null +++ b/vendor/vaimo/webdriver-binary-downloader/src/Interfaces/PlatformAnalyserInterface.php @@ -0,0 +1,27 @@ + Date: Tue, 29 Sep 2020 14:15:23 +0200 Subject: [PATCH 02/23] Fixtures can be loaded (fix of #1905) --- .env.dist | 2 +- src/Entity/FieldTranslation.php | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.env.dist b/.env.dist index d7168e55c..5b7015f81 100644 --- a/.env.dist +++ b/.env.dist @@ -24,7 +24,7 @@ DATABASE_URL=sqlite:///%kernel.project_dir%/var/data/bolt.sqlite #DATABASE_URL=mysql://db_user:"db_password"@localhost:3306/db_name # Postgres -#DATABASE_URL=postgresql://db_user:"db_password"@localhost:5432/db_name?serverVersion=11" +#DATABASE_URL=postgresql://db_user:"db_password"@localhost:5432/db_name?serverVersion=11&charset=utf8" # MYSQL / MariaDB (additional settings, needed for Docker) #DATABASE_USER=db_user diff --git a/src/Entity/FieldTranslation.php b/src/Entity/FieldTranslation.php index dc7aad5e6..15d250ea8 100644 --- a/src/Entity/FieldTranslation.php +++ b/src/Entity/FieldTranslation.php @@ -21,7 +21,7 @@ class FieldTranslation implements TranslationInterface */ private $id; - /** @ORM\Column(type="json") */ + /** @ORM\Column(type="json", options={"jsonb": true}) */ protected $value = []; public function getId(): ?int From 22dafbae72c62c9fe9e9068955b40f14ff7d5a28 Mon Sep 17 00:00:00 2001 From: Wytse Talsma Date: Tue, 29 Sep 2020 14:32:44 +0200 Subject: [PATCH 03/23] Bypassing lower-case search bug: BUG SQLSTATE[42883]: Undefined function: 7 ERROR: function lower(jsonb) does not exist --- src/Storage/SelectQuery.php | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/Storage/SelectQuery.php b/src/Storage/SelectQuery.php index dd5ab67fb..6effbcaad 100644 --- a/src/Storage/SelectQuery.php +++ b/src/Storage/SelectQuery.php @@ -533,10 +533,14 @@ private function getRegularFieldExpression(Filter $filter, EntityManagerInterfac $originalLeftExpression = 'content.' . $filter->getKey(); // LOWER() added to query to enable case insensitive search of JSON values. Used in conjunction with converting $params of setParameter() to lowercase. - $newLeftExpression = JsonHelper::wrapJsonFunction('LOWER(' . $valueAlias . ')', null, $em->getConnection()); + // BUG SQLSTATE[42883]: Undefined function: 7 ERROR: function lower(jsonb) does not exist + // I dont care about case-insensitive search at this point, just fixing this by removing this method + //$newLeftExpression = JsonHelper::wrapJsonFunction('LOWER(' . $valueAlias . ')', null, $em->getConnection()); + $newLeftExpression = JsonHelper::wrapJsonFunction($valueAlias, null, $em->getConnection()); $valueWhere = $filter->getExpression(); $valueWhere = str_replace($originalLeftExpression, $newLeftExpression, $valueWhere); $expr->add($valueWhere); + // @todo: Filter non-standalone fields (i.e. fields with parents) $null = $this->qb->expr()->isNull(sprintf('fields_%s.parent', $filter->getKey())); From b9934e6fc8e336d1b60e93df651b9c3f6bd48117 Mon Sep 17 00:00:00 2001 From: Wytse Talsma Date: Tue, 29 Sep 2020 15:11:05 +0200 Subject: [PATCH 04/23] Missing assets due to wrong order in README --- README.md | 25 +++++++++++++------------ 1 file changed, 13 insertions(+), 12 deletions(-) diff --git a/README.md b/README.md index e08f333e5..2d473b0e2 100644 --- a/README.md +++ b/README.md @@ -117,7 +117,19 @@ bin/console doctrine:fixtures:load -n Alternatively, run `make db-reset`, on a UNIX-like system. -4 Run the prototype +4 How to build assets +------------------- + +To set up initially, run `npm install` to get the required dependencies / +`node_modules`. Alternatively give the path to the python executable (`npm install --python="/usr/local/bin/python3.7"`) Then: + - Prepare directory structure `mkdir -p node_modules/node-sass/vendor` + - Rebuild npm environment for current OS `npm rebuild node-sass` + - Run `npm run start` (alternatively `npm run start --python="/usr/local/bin/python3.7"`) + +See the other options by running `npm run`. +(Note: as I'm testing this as well remotely, I copied all assets from the released composer installation by `cp -r ../www_backup/public/assets/* public/assets/`) + +5 Run the prototype ------------------- - Using the Symfony CLI tool, just run `symfony server:start`. @@ -134,17 +146,6 @@ You can log on, using the default user & pass: - pass: `admin%1` -How to build assets -------------------- - -To set up initially, run `npm install` to get the required dependencies / -`node_modules`. Then: - - - Run `npm run start` - -See the other options by running `npm run`. - - Code Style checking / Static Analysis ---------------------------- From b070b4a0e05624b79df62a75983c11fd417b32e4 Mon Sep 17 00:00:00 2001 From: Wytse Talsma Date: Tue, 29 Sep 2020 15:15:35 +0200 Subject: [PATCH 05/23] Bugfix for admin login to log. SQLSTATE[42601]: Syntax error: 7 ERROR: syntax error at or near user - user is a protected name and need quotation! --- src/Entity/Log.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Entity/Log.php b/src/Entity/Log.php index b209a76b6..0862e4940 100644 --- a/src/Entity/Log.php +++ b/src/Entity/Log.php @@ -38,7 +38,7 @@ class Log /** @ORM\Column(name="extra", type="array", nullable=true) */ private $extra; - /** @ORM\Column(name="user", type="array", nullable=true) */ + /** @ORM\Column(name="`user`", type="array", nullable=true) */ private $user; /** @ORM\Column(type="content", type="integer", nullable=true) */ From ed7396db4d1ec512f3c33f462fcfaee4769d5830 Mon Sep 17 00:00:00 2001 From: Wytse Talsma Date: Tue, 29 Sep 2020 16:57:06 +0200 Subject: [PATCH 06/23] Fixed RandomSelect for records in PostgreSQL --- src/Doctrine/Functions/Rand.php | 5 +++++ src/Storage/Directive/RandomDirectiveHandler.php | 5 +++++ 2 files changed, 10 insertions(+) diff --git a/src/Doctrine/Functions/Rand.php b/src/Doctrine/Functions/Rand.php index 6637b85b6..b637ea05c 100644 --- a/src/Doctrine/Functions/Rand.php +++ b/src/Doctrine/Functions/Rand.php @@ -19,6 +19,11 @@ public function getSql(\Doctrine\ORM\Query\SqlWalker $sqlWalker) if (property_exists($this->expression, 'value') && $this->expression->value === '1') { return 'random()'; } + // value is two if PostgreSQL. See Bolt\Storage\Directive\RandomDirectiveHandler + if (property_exists($this->expression, 'value') && $this->expression->value === '2') { + return 'RANDOM()'; + } + return 'RAND()'; } diff --git a/src/Storage/Directive/RandomDirectiveHandler.php b/src/Storage/Directive/RandomDirectiveHandler.php index b2a2bbeb5..df88c9a76 100644 --- a/src/Storage/Directive/RandomDirectiveHandler.php +++ b/src/Storage/Directive/RandomDirectiveHandler.php @@ -29,6 +29,11 @@ public function __invoke(QueryInterface $query, $value, &$directives): void if ($this->version->getPlatform()['driver_name'] === 'sqlite') { $query->getQueryBuilder()->addSelect('RAND(1) as HIDDEN rand')->orderBy('rand'); + return; + } if ($this->version->getPlatform()['driver_name'] === 'pgsql') { + $query->getQueryBuilder()->addSelect('RAND(2) as HIDDEN rand')->orderBy('rand'); + //$debug_msg = $query->getQueryBuilder()->getQuery()->getSQL(); + //throw new Exception($debug_msg); return; } From ad555b253eaf76534d981d3401adc9081f9a771d Mon Sep 17 00:00:00 2001 From: Wytse Talsma Date: Tue, 29 Sep 2020 17:04:19 +0200 Subject: [PATCH 07/23] Ran Code Style checking / Static Analysis --- config/extensions/acmecorp-referenceextension.yaml | 3 +++ src/.preload.php | 5 +++++ src/Doctrine/Functions/Rand.php | 1 - src/Storage/Directive/RandomDirectiveHandler.php | 3 ++- src/Storage/SelectQuery.php | 1 - 5 files changed, 10 insertions(+), 3 deletions(-) create mode 100644 config/extensions/acmecorp-referenceextension.yaml create mode 100644 src/.preload.php diff --git a/config/extensions/acmecorp-referenceextension.yaml b/config/extensions/acmecorp-referenceextension.yaml new file mode 100644 index 000000000..ca0e2017e --- /dev/null +++ b/config/extensions/acmecorp-referenceextension.yaml @@ -0,0 +1,3 @@ +# Reference extension configuration file + +foo: Bar diff --git a/src/.preload.php b/src/.preload.php new file mode 100644 index 000000000..a1ff84878 --- /dev/null +++ b/src/.preload.php @@ -0,0 +1,5 @@ +getQueryBuilder()->addSelect('RAND(1) as HIDDEN rand')->orderBy('rand'); return; - } if ($this->version->getPlatform()['driver_name'] === 'pgsql') { + } + if ($this->version->getPlatform()['driver_name'] === 'pgsql') { $query->getQueryBuilder()->addSelect('RAND(2) as HIDDEN rand')->orderBy('rand'); //$debug_msg = $query->getQueryBuilder()->getQuery()->getSQL(); //throw new Exception($debug_msg); diff --git a/src/Storage/SelectQuery.php b/src/Storage/SelectQuery.php index 6effbcaad..d4e72b20d 100644 --- a/src/Storage/SelectQuery.php +++ b/src/Storage/SelectQuery.php @@ -540,7 +540,6 @@ private function getRegularFieldExpression(Filter $filter, EntityManagerInterfac $valueWhere = $filter->getExpression(); $valueWhere = str_replace($originalLeftExpression, $newLeftExpression, $valueWhere); $expr->add($valueWhere); - // @todo: Filter non-standalone fields (i.e. fields with parents) $null = $this->qb->expr()->isNull(sprintf('fields_%s.parent', $filter->getKey())); From f85fd41a68b0de71db602d7070f74beb6aeb6652 Mon Sep 17 00:00:00 2001 From: Wytse Talsma Date: Tue, 29 Sep 2020 18:49:24 +0200 Subject: [PATCH 08/23] Fixed search function for PostgreSQL and jsonb --- src/Repository/ContentRepository.php | 2 +- src/Storage/SelectQuery.php | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Repository/ContentRepository.php b/src/Repository/ContentRepository.php index ad5644d3a..b201675b7 100644 --- a/src/Repository/ContentRepository.php +++ b/src/Repository/ContentRepository.php @@ -97,7 +97,7 @@ public function searchNaive(string $searchTerm, int $page, int $amountPerPage, C $qb->addSelect('f') ->innerJoin('content.fields', 'f') ->innerJoin('f.translations', 't') - ->andWhere($qb->expr()->like('t.value', ':search')) + ->andWhere($qb->expr()->like('CAST(t.value AS TEXT)', ':search')) ->setParameter('search', '%' . $searchTerm . '%'); // These are the ID's of content we need. diff --git a/src/Storage/SelectQuery.php b/src/Storage/SelectQuery.php index d4e72b20d..ff651b31a 100644 --- a/src/Storage/SelectQuery.php +++ b/src/Storage/SelectQuery.php @@ -534,8 +534,8 @@ private function getRegularFieldExpression(Filter $filter, EntityManagerInterfac $originalLeftExpression = 'content.' . $filter->getKey(); // LOWER() added to query to enable case insensitive search of JSON values. Used in conjunction with converting $params of setParameter() to lowercase. // BUG SQLSTATE[42883]: Undefined function: 7 ERROR: function lower(jsonb) does not exist - // I dont care about case-insensitive search at this point, just fixing this by removing this method - //$newLeftExpression = JsonHelper::wrapJsonFunction('LOWER(' . $valueAlias . ')', null, $em->getConnection()); + // We want to be able to search case-insensitive, database-agnostic + $valueAlias = mb_strtolower($valueAlias); $newLeftExpression = JsonHelper::wrapJsonFunction($valueAlias, null, $em->getConnection()); $valueWhere = $filter->getExpression(); $valueWhere = str_replace($originalLeftExpression, $newLeftExpression, $valueWhere); From 2707e714f340cd533314d033c6fbfa526884ea63 Mon Sep 17 00:00:00 2001 From: Wytse Talsma Date: Thu, 1 Oct 2020 00:10:26 +0200 Subject: [PATCH 09/23] Fixed the search/CAST for MySQL - JSON is already considered TEXT in MySQL --- config/packages/doctrine.yaml | 3 +- src/Doctrine/Query/Cast.php | 53 ++++++++++++++++++++++++++++ src/Repository/ContentRepository.php | 4 +++ 3 files changed, 59 insertions(+), 1 deletion(-) create mode 100644 src/Doctrine/Query/Cast.php diff --git a/config/packages/doctrine.yaml b/config/packages/doctrine.yaml index 853b28ee2..d1095a89c 100644 --- a/config/packages/doctrine.yaml +++ b/config/packages/doctrine.yaml @@ -32,7 +32,8 @@ doctrine: dql: string_functions: JSON_EXTRACT: Bolt\Doctrine\Functions\JsonExtract - CAST: DoctrineExtensions\Query\Mysql\Cast + # CAST: DoctrineExtensions\Query\Mysql\Cast + CAST: Bolt\Doctrine\Query\Cast numeric_functions: RAND: Bolt\Doctrine\Functions\Rand diff --git a/src/Doctrine/Query/Cast.php b/src/Doctrine/Query/Cast.php new file mode 100644 index 000000000..ae6b1f916 --- /dev/null +++ b/src/Doctrine/Query/Cast.php @@ -0,0 +1,53 @@ +getConnection()->getDriver()->getName(); + // test if we are using MySQL + if (mb_strpos($backend_driver, 'mysql') !== false) { + // how do we know what type $this->first is? For now hardcoding + // type(t.value) = JSON for MySQL. JSONB for others. + // alternatively, test if true: $this->first->dispatch($sqlWalker)==='b2_.value' + if ($this->first->identificationVariable === 't' && $this->first->field === 'value' && $this->second === 'TEXT') { + return $this->first->dispatch($sqlWalker); + } + } + + return sprintf('CAST(%s AS %s)', + $this->first->dispatch($sqlWalker), + $this->second + ); + } + + public function parse(Parser $parser): void + { + $parser->match(Lexer::T_IDENTIFIER); + $parser->match(Lexer::T_OPEN_PARENTHESIS); + $this->first = $parser->ArithmeticPrimary(); + $parser->match(Lexer::T_AS); + $parser->match(Lexer::T_IDENTIFIER); + $this->second = $parser->getLexer()->token['value']; + $parser->match(Lexer::T_CLOSE_PARENTHESIS); + } +} diff --git a/src/Repository/ContentRepository.php b/src/Repository/ContentRepository.php index b201675b7..96d94ee6f 100644 --- a/src/Repository/ContentRepository.php +++ b/src/Repository/ContentRepository.php @@ -94,6 +94,10 @@ public function searchNaive(string $searchTerm, int $page, int $amountPerPage, C $qb = $this->getQueryBuilder() ->select('partial content.{id}'); + // For PostgreSQL we need to CAST the jsonb to text. For SQLite this is not required but also works + // For mysql however, an error is thrown. the JSON can be directly searched without CAST. + // So, there is need for a custom CAST function, which reacts when json/b is casted to text + // this can probably be more efficient by a seperate ->Cast implementation $qb->addSelect('f') ->innerJoin('content.fields', 'f') ->innerJoin('f.translations', 't') From c68e6d5516077587f69185ef18be8af3a71cb240 Mon Sep 17 00:00:00 2001 From: Wytse Talsma Date: Thu, 1 Oct 2020 00:56:23 +0200 Subject: [PATCH 10/23] found strange bug, partial fix --- templates/helpers/_field_blocks.twig | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/templates/helpers/_field_blocks.twig b/templates/helpers/_field_blocks.twig index c276284f2..a88b7afb5 100644 --- a/templates/helpers/_field_blocks.twig +++ b/templates/helpers/_field_blocks.twig @@ -43,11 +43,14 @@ {% block extended_fields %} {# Special case for 'select' fields: if it's a multiple select, the field is an array. #} + {# I dont know what is going on here, but field.selectedIds for pgsql showcase/mr-jean-feeney (and others) #} + {# yield field values, NOT integer IDs.. Also, selectedIds does not exists (try dump(field) ) #} + {# TODO: FIX IT, bypassing for now by setting field.id #} {% if type == "select" and field is not empty %}

{{ field|label }}:

    {% if field.contentSelect %} - {% setcontent selected = field.contentType where {'id': field.selectedIds} %} + {% setcontent selected = field.contentType where {'id': field.id} %} {% for record in selected %}
  • {{ record|title }}
  • {% endfor %} From 4729e763c0b3f6950bff6ebfbb5faaae26675e28 Mon Sep 17 00:00:00 2001 From: Wytse Talsma Date: Fri, 2 Oct 2020 11:24:09 +0200 Subject: [PATCH 11/23] Minor cleanup and fix --- src/Doctrine/Query/Cast.php | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/Doctrine/Query/Cast.php b/src/Doctrine/Query/Cast.php index ae6b1f916..23d407322 100644 --- a/src/Doctrine/Query/Cast.php +++ b/src/Doctrine/Query/Cast.php @@ -1,8 +1,5 @@ Date: Fri, 2 Oct 2020 12:54:55 +0200 Subject: [PATCH 12/23] Lower is breaking more than gaining --- src/Storage/SelectQuery.php | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/Storage/SelectQuery.php b/src/Storage/SelectQuery.php index ff651b31a..a9d9d85bc 100644 --- a/src/Storage/SelectQuery.php +++ b/src/Storage/SelectQuery.php @@ -535,7 +535,10 @@ private function getRegularFieldExpression(Filter $filter, EntityManagerInterfac // LOWER() added to query to enable case insensitive search of JSON values. Used in conjunction with converting $params of setParameter() to lowercase. // BUG SQLSTATE[42883]: Undefined function: 7 ERROR: function lower(jsonb) does not exist // We want to be able to search case-insensitive, database-agnostic - $valueAlias = mb_strtolower($valueAlias); + // NO, this causes another problems: + // [Semantical Error] line 0, col 373 near 'translations_anyfield.value': Error: 'translations_anyfield' is not defined. + // --> should be: translations_anyField! capital F. (while searching in https://../bolt/?filter=css) + // $valueAlias = mb_strtolower($valueAlias); $newLeftExpression = JsonHelper::wrapJsonFunction($valueAlias, null, $em->getConnection()); $valueWhere = $filter->getExpression(); $valueWhere = str_replace($originalLeftExpression, $newLeftExpression, $valueWhere); From d9c23121fd39640c226d5f68ad23639334d6b165 Mon Sep 17 00:00:00 2001 From: Wytse Talsma Date: Sun, 4 Oct 2020 00:41:01 +0200 Subject: [PATCH 13/23] Fully postgres/mysql compatible --- config/packages/doctrine.yaml | 4 +++- src/Doctrine/JsonHelper.php | 12 +++++++++++- src/Doctrine/Version.php | 6 ++++++ src/Repository/ContentRepository.php | 10 +++++----- 4 files changed, 25 insertions(+), 7 deletions(-) diff --git a/config/packages/doctrine.yaml b/config/packages/doctrine.yaml index d1095a89c..406db3608 100644 --- a/config/packages/doctrine.yaml +++ b/config/packages/doctrine.yaml @@ -31,7 +31,9 @@ doctrine: alias: App dql: string_functions: - JSON_EXTRACT: Bolt\Doctrine\Functions\JsonExtract + JSON_EXTRACT: Bolt\Doctrine\Functions\JsonExtract # Why have a duplicate of the Scienta version? + # JSON_EXTRACT_PATH: Scienta\DoctrineJsonFunctions\Query\AST\Functions\Postgresql\JsonExtractPath + JSON_GET_TEXT: Scienta\DoctrineJsonFunctions\Query\AST\Functions\Postgresql\JsonGetText # CAST: DoctrineExtensions\Query\Mysql\Cast CAST: Bolt\Doctrine\Query\Cast numeric_functions: diff --git a/src/Doctrine/JsonHelper.php b/src/Doctrine/JsonHelper.php index d11de3ac3..125d1d172 100644 --- a/src/Doctrine/JsonHelper.php +++ b/src/Doctrine/JsonHelper.php @@ -23,9 +23,19 @@ class JsonHelper public static function wrapJsonFunction(?string $where = null, ?string $slug = null, Connection $connection) { $version = new Version($connection); + //print_r($version->getPlatform()['driver_name']); # pgsql + //exit(print($where)); // translations_anyField.value if ($version->hasJson()) { - $resultWhere = 'JSON_EXTRACT(' . $where . ", '$[0]')"; + //PostgreSQL handles JSON differently than MySQL + if ($version->getPlatform()['driver_name'] === 'pgsql') { + // PostgreSQL + $resultWhere = 'JSON_GET_TEXT(' . $where . ', 0)'; + } else { + // MySQL and SQLite + $resultWhere = 'JSON_EXTRACT(' . $where . ", '$[0]')"; + } + //exit($resultWhere); $resultSlug = $slug; } else { $resultWhere = $where; diff --git a/src/Doctrine/Version.php b/src/Doctrine/Version.php index 9fb914125..b8b3b7644 100644 --- a/src/Doctrine/Version.php +++ b/src/Doctrine/Version.php @@ -9,6 +9,7 @@ use Doctrine\DBAL\Driver\PDOConnection; use Doctrine\DBAL\Platforms\MariaDb1027Platform; use Doctrine\DBAL\Platforms\MySQL57Platform; +use Doctrine\DBAL\Platforms\PostgreSQL92Platform; use Doctrine\DBAL\Platforms\SqlitePlatform; class Version @@ -87,6 +88,11 @@ public function hasJson(): bool return true; } + // PostgreSQL supports JSON from v9.2 and above, later versions are implicitly included + if ($platform instanceof PostgreSQL92Platform) { + return true; + } + return false; } diff --git a/src/Repository/ContentRepository.php b/src/Repository/ContentRepository.php index 96d94ee6f..bad3589b5 100644 --- a/src/Repository/ContentRepository.php +++ b/src/Repository/ContentRepository.php @@ -94,14 +94,14 @@ public function searchNaive(string $searchTerm, int $page, int $amountPerPage, C $qb = $this->getQueryBuilder() ->select('partial content.{id}'); - // For PostgreSQL we need to CAST the jsonb to text. For SQLite this is not required but also works - // For mysql however, an error is thrown. the JSON can be directly searched without CAST. - // So, there is need for a custom CAST function, which reacts when json/b is casted to text - // this can probably be more efficient by a seperate ->Cast implementation + // proper JSON wrapping solves a lot of problems (added PostgreSQL compatibility) + $connection = $qb->getEntityManager()->getConnection(); + [$where, $searchTerm] = JsonHelper::wrapJsonFunction('t.value', $searchTerm, $connection); + $qb->addSelect('f') ->innerJoin('content.fields', 'f') ->innerJoin('f.translations', 't') - ->andWhere($qb->expr()->like('CAST(t.value AS TEXT)', ':search')) + ->andWhere($qb->expr()->like($where, ':search')) ->setParameter('search', '%' . $searchTerm . '%'); // These are the ID's of content we need. From d3b2e2bdfea58c7c16008b5ec1e66db6aec04221 Mon Sep 17 00:00:00 2001 From: Wytse Talsma Date: Sun, 4 Oct 2020 22:29:13 +0200 Subject: [PATCH 14/23] Some cleanup --- .gitignore | 4 ++++ config/extensions/acmecorp-referenceextension.yaml | 3 --- src/.preload.php | 5 ----- src/Doctrine/JsonHelper.php | 3 --- src/Storage/Directive/RandomDirectiveHandler.php | 2 -- src/Storage/SelectQuery.php | 6 +----- 6 files changed, 5 insertions(+), 18 deletions(-) delete mode 100644 config/extensions/acmecorp-referenceextension.yaml delete mode 100644 src/.preload.php diff --git a/.gitignore b/.gitignore index 69889c194..a14c6e815 100644 --- a/.gitignore +++ b/.gitignore @@ -92,3 +92,7 @@ appveyor.yml ###> phpunit/phpunit ### /phpunit.xml ###< phpunit/phpunit ### + +###> .preload dev ### +/src/.preload.php +###< .preload dev ### diff --git a/config/extensions/acmecorp-referenceextension.yaml b/config/extensions/acmecorp-referenceextension.yaml deleted file mode 100644 index ca0e2017e..000000000 --- a/config/extensions/acmecorp-referenceextension.yaml +++ /dev/null @@ -1,3 +0,0 @@ -# Reference extension configuration file - -foo: Bar diff --git a/src/.preload.php b/src/.preload.php deleted file mode 100644 index a1ff84878..000000000 --- a/src/.preload.php +++ /dev/null @@ -1,5 +0,0 @@ -getPlatform()['driver_name']); # pgsql - //exit(print($where)); // translations_anyField.value if ($version->hasJson()) { //PostgreSQL handles JSON differently than MySQL @@ -35,7 +33,6 @@ public static function wrapJsonFunction(?string $where = null, ?string $slug = n // MySQL and SQLite $resultWhere = 'JSON_EXTRACT(' . $where . ", '$[0]')"; } - //exit($resultWhere); $resultSlug = $slug; } else { $resultWhere = $where; diff --git a/src/Storage/Directive/RandomDirectiveHandler.php b/src/Storage/Directive/RandomDirectiveHandler.php index 37679ee83..72b5b55eb 100644 --- a/src/Storage/Directive/RandomDirectiveHandler.php +++ b/src/Storage/Directive/RandomDirectiveHandler.php @@ -33,8 +33,6 @@ public function __invoke(QueryInterface $query, $value, &$directives): void } if ($this->version->getPlatform()['driver_name'] === 'pgsql') { $query->getQueryBuilder()->addSelect('RAND(2) as HIDDEN rand')->orderBy('rand'); - //$debug_msg = $query->getQueryBuilder()->getQuery()->getSQL(); - //throw new Exception($debug_msg); return; } diff --git a/src/Storage/SelectQuery.php b/src/Storage/SelectQuery.php index a9d9d85bc..1127b96a4 100644 --- a/src/Storage/SelectQuery.php +++ b/src/Storage/SelectQuery.php @@ -534,11 +534,7 @@ private function getRegularFieldExpression(Filter $filter, EntityManagerInterfac $originalLeftExpression = 'content.' . $filter->getKey(); // LOWER() added to query to enable case insensitive search of JSON values. Used in conjunction with converting $params of setParameter() to lowercase. // BUG SQLSTATE[42883]: Undefined function: 7 ERROR: function lower(jsonb) does not exist - // We want to be able to search case-insensitive, database-agnostic - // NO, this causes another problems: - // [Semantical Error] line 0, col 373 near 'translations_anyfield.value': Error: 'translations_anyfield' is not defined. - // --> should be: translations_anyField! capital F. (while searching in https://../bolt/?filter=css) - // $valueAlias = mb_strtolower($valueAlias); + // We want to be able to search case-insensitive, database-agnostic, have to think of a good way.. $newLeftExpression = JsonHelper::wrapJsonFunction($valueAlias, null, $em->getConnection()); $valueWhere = $filter->getExpression(); $valueWhere = str_replace($originalLeftExpression, $newLeftExpression, $valueWhere); From fea65d4910db636428b601be2c3d41495c43e801 Mon Sep 17 00:00:00 2001 From: Wytse Talsma Date: Mon, 5 Oct 2020 09:59:06 +0200 Subject: [PATCH 15/23] Further cleanup & fix of showcase editability in postgres --- config/packages/doctrine.yaml | 4 +--- src/Doctrine/Query/Cast.php | 9 +++++++-- src/Storage/Directive/OrderDirective.php | 3 ++- src/Storage/SelectQuery.php | 2 +- templates/helpers/_field_blocks.twig | 6 +++--- 5 files changed, 14 insertions(+), 10 deletions(-) diff --git a/config/packages/doctrine.yaml b/config/packages/doctrine.yaml index 406db3608..4275d408a 100644 --- a/config/packages/doctrine.yaml +++ b/config/packages/doctrine.yaml @@ -31,10 +31,8 @@ doctrine: alias: App dql: string_functions: - JSON_EXTRACT: Bolt\Doctrine\Functions\JsonExtract # Why have a duplicate of the Scienta version? - # JSON_EXTRACT_PATH: Scienta\DoctrineJsonFunctions\Query\AST\Functions\Postgresql\JsonExtractPath + JSON_EXTRACT: Bolt\Doctrine\Functions\JsonExtract JSON_GET_TEXT: Scienta\DoctrineJsonFunctions\Query\AST\Functions\Postgresql\JsonGetText - # CAST: DoctrineExtensions\Query\Mysql\Cast CAST: Bolt\Doctrine\Query\Cast numeric_functions: RAND: Bolt\Doctrine\Functions\Rand diff --git a/src/Doctrine/Query/Cast.php b/src/Doctrine/Query/Cast.php index 23d407322..5c9db97ed 100644 --- a/src/Doctrine/Query/Cast.php +++ b/src/Doctrine/Query/Cast.php @@ -21,12 +21,17 @@ class Cast extends FunctionNode public function getSql(SqlWalker $sqlWalker): string { $backend_driver = $sqlWalker->getConnection()->getDriver()->getName(); + // test if we are using MySQL if (mb_strpos($backend_driver, 'mysql') !== false) { + // YES we are using MySQL // how do we know what type $this->first is? For now hardcoding // type(t.value) = JSON for MySQL. JSONB for others. - // alternatively, test if true: $this->first->dispatch($sqlWalker)==='b2_.value' - if ($this->first->identificationVariable === 't' && $this->first->field === 'value' && $this->second === 'TEXT') { + // alternatively, test if true: $this->first->dispatch($sqlWalker)==='b2_.value', + // b4_.value for /bolt/new/showcases + if ($this->first->dispatch($sqlWalker)==='b2_.value' || + $this->first->dispatch($sqlWalker)==='b4_.value') + { return $this->first->dispatch($sqlWalker); } } diff --git a/src/Storage/Directive/OrderDirective.php b/src/Storage/Directive/OrderDirective.php index 6fcfcc08b..a92b3727b 100644 --- a/src/Storage/Directive/OrderDirective.php +++ b/src/Storage/Directive/OrderDirective.php @@ -115,9 +115,10 @@ private function setOrderBy(QueryInterface $query, string $order, string $direct } else { // Note the `lower()` in the `addOrderBy()`. It is essential to sorting the // results correctly. See also https://github.com/bolt/core/issues/1190 + // again: lower breaks postgresql jsonb compatibility, first cast as txt $query ->getQueryBuilder() - ->addOrderBy('lower(' . $translationsAlias . '.value)', $direction); + ->addOrderBy('lower(CAST(' . $translationsAlias . '.value as TEXT))', $direction); } $query->incrementIndex(); } else { diff --git a/src/Storage/SelectQuery.php b/src/Storage/SelectQuery.php index 1127b96a4..90ae3d151 100644 --- a/src/Storage/SelectQuery.php +++ b/src/Storage/SelectQuery.php @@ -534,7 +534,7 @@ private function getRegularFieldExpression(Filter $filter, EntityManagerInterfac $originalLeftExpression = 'content.' . $filter->getKey(); // LOWER() added to query to enable case insensitive search of JSON values. Used in conjunction with converting $params of setParameter() to lowercase. // BUG SQLSTATE[42883]: Undefined function: 7 ERROR: function lower(jsonb) does not exist - // We want to be able to search case-insensitive, database-agnostic, have to think of a good way.. + // We want to be able to search case-insensitive, database-agnostic, have to think of a good way.. $newLeftExpression = JsonHelper::wrapJsonFunction($valueAlias, null, $em->getConnection()); $valueWhere = $filter->getExpression(); $valueWhere = str_replace($originalLeftExpression, $newLeftExpression, $valueWhere); diff --git a/templates/helpers/_field_blocks.twig b/templates/helpers/_field_blocks.twig index a88b7afb5..47e22666c 100644 --- a/templates/helpers/_field_blocks.twig +++ b/templates/helpers/_field_blocks.twig @@ -44,13 +44,13 @@ {# Special case for 'select' fields: if it's a multiple select, the field is an array. #} {# I dont know what is going on here, but field.selectedIds for pgsql showcase/mr-jean-feeney (and others) #} - {# yield field values, NOT integer IDs.. Also, selectedIds does not exists (try dump(field) ) #} - {# TODO: FIX IT, bypassing for now by setting field.id #} + {# yield field values (strings containing full name!), NOT integer IDs.. #} + {# TODO: FIX IT, bypassing for now by selecting on 'value' (string) and not 'id' (int) #} {% if type == "select" and field is not empty %}

    {{ field|label }}:

      {% if field.contentSelect %} - {% setcontent selected = field.contentType where {'id': field.id} %} + {% setcontent selected = field.contentType where {'value': field.selectedIds} %} {% for record in selected %}
    • {{ record|title }}
    • {% endfor %} From cc659b228b6ca91127e8fc64c9051c7416fb7328 Mon Sep 17 00:00:00 2001 From: Wytse Talsma Date: Mon, 5 Oct 2020 10:14:17 +0200 Subject: [PATCH 16/23] style fixes --- src/Doctrine/Query/Cast.php | 7 +++---- src/Storage/Directive/RandomDirectiveHandler.php | 1 + 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/Doctrine/Query/Cast.php b/src/Doctrine/Query/Cast.php index 5c9db97ed..79b49caed 100644 --- a/src/Doctrine/Query/Cast.php +++ b/src/Doctrine/Query/Cast.php @@ -27,11 +27,10 @@ public function getSql(SqlWalker $sqlWalker): string // YES we are using MySQL // how do we know what type $this->first is? For now hardcoding // type(t.value) = JSON for MySQL. JSONB for others. - // alternatively, test if true: $this->first->dispatch($sqlWalker)==='b2_.value', + // alternatively, test if true: $this->first->dispatch($sqlWalker)==='b2_.value', // b4_.value for /bolt/new/showcases - if ($this->first->dispatch($sqlWalker)==='b2_.value' || - $this->first->dispatch($sqlWalker)==='b4_.value') - { + if ($this->first->dispatch($sqlWalker) === 'b2_.value' || + $this->first->dispatch($sqlWalker) === 'b4_.value') { return $this->first->dispatch($sqlWalker); } } diff --git a/src/Storage/Directive/RandomDirectiveHandler.php b/src/Storage/Directive/RandomDirectiveHandler.php index 72b5b55eb..8eb7b679e 100644 --- a/src/Storage/Directive/RandomDirectiveHandler.php +++ b/src/Storage/Directive/RandomDirectiveHandler.php @@ -33,6 +33,7 @@ public function __invoke(QueryInterface $query, $value, &$directives): void } if ($this->version->getPlatform()['driver_name'] === 'pgsql') { $query->getQueryBuilder()->addSelect('RAND(2) as HIDDEN rand')->orderBy('rand'); + return; } From f873aef63ea7f9ab9b4fd78836a34a86e1ff9c65 Mon Sep 17 00:00:00 2001 From: Wytse Talsma Date: Mon, 5 Oct 2020 11:35:03 +0200 Subject: [PATCH 17/23] Fix search bug SQLite that appeared since inclusion in JSONwrapper - PHP supports SQLite since version 5.3.0 --- src/Doctrine/Version.php | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/Doctrine/Version.php b/src/Doctrine/Version.php index b8b3b7644..533d01461 100644 --- a/src/Doctrine/Version.php +++ b/src/Doctrine/Version.php @@ -17,6 +17,8 @@ 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: + * https://www.sqlite.org/json1.html --> JSON since SQLite version 3.9.0 (2015-10-14) + * - 3.32.2 - OK (Wytse's FBSD 12.1 \w PHP 7.2) * - 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) @@ -24,8 +26,10 @@ class Version * - 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'; + // JSON supported since SQLite version 3.9.0 + public const SQLITE_WITH_JSON = '3.9.0'; + // PHP supports SQLite since version 5.3.0 + public const PHP_WITH_SQLITE = '5.3.0'; /** @var Connection */ private $connection; From d7ab4a01d2887c5ef636b604978b3bbf121e6d47 Mon Sep 17 00:00:00 2001 From: Wytse Talsma Date: Mon, 5 Oct 2020 12:21:35 +0200 Subject: [PATCH 18/23] Trying to get test to pass for SQLite in Docker --- src/Doctrine/Version.php | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/Doctrine/Version.php b/src/Doctrine/Version.php index 533d01461..fd3dccede 100644 --- a/src/Doctrine/Version.php +++ b/src/Doctrine/Version.php @@ -18,6 +18,10 @@ 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: * https://www.sqlite.org/json1.html --> JSON since SQLite version 3.9.0 (2015-10-14) + * Docker uses an outdated version of SQLite/PHP combi with wrong implementation of JSON1 extensions: + * https://www.talvbansal.me/blog/unit-tests-with-json-columns-in-sqlite/ + * This explains why BOLT is working in stand-alone production/dev envs. but not in unit tests using Docker + * We need to replace this with a proper function test, instead of a guestimate. * - 3.32.2 - OK (Wytse's FBSD 12.1 \w PHP 7.2) * - 3.20.1 - Not OK (Travis PHP 7.2) * - 3.27.2 - OK (Bob's Raspberry Pi, running PHP 7.3.11 on Raspbian) @@ -27,7 +31,7 @@ class Version * - 3.30.1 - OK (MacOS Catalina) */ // JSON supported since SQLite version 3.9.0 - public const SQLITE_WITH_JSON = '3.9.0'; + public const SQLITE_WITH_JSON = '3.32.0'; // PHP supports SQLite since version 5.3.0 public const PHP_WITH_SQLITE = '5.3.0'; From e827a7990e42d2ab85dfbdd636a4777d8ea1532e Mon Sep 17 00:00:00 2001 From: Wytse Talsma Date: Mon, 5 Oct 2020 14:26:38 +0200 Subject: [PATCH 19/23] improved sqlite json checking --- src/Doctrine/Version.php | 51 ++++++++++++++++++++++++++++++---------- 1 file changed, 38 insertions(+), 13 deletions(-) diff --git a/src/Doctrine/Version.php b/src/Doctrine/Version.php index fd3dccede..fd7e37146 100644 --- a/src/Doctrine/Version.php +++ b/src/Doctrine/Version.php @@ -31,9 +31,9 @@ class Version * - 3.30.1 - OK (MacOS Catalina) */ // JSON supported since SQLite version 3.9.0 - public const SQLITE_WITH_JSON = '3.32.0'; - // PHP supports SQLite since version 5.3.0 - public const PHP_WITH_SQLITE = '5.3.0'; + public const SQLITE_WITH_JSON = '3.27.0'; + // PHP supports SQLite since version 5.3.0, but not always bundled with JSON support! + public const PHP_WITH_SQLITE_JSON_SUPPORT = '7.3.0'; /** @var Connection */ private $connection; @@ -88,7 +88,11 @@ public function hasJson(): bool $platform = $this->connection->getDatabasePlatform(); if ($platform instanceof SqlitePlatform) { - return $this->checkSqliteVersion(); + // new method to test for JSON support + return $this->hasSQLiteJSONSupport(); + + // temporarily leave this in, until above method is fully tested + // return $this->checkSqliteVersion(); } // MySQL80Platform is implicitly included with MySQL57Platform @@ -118,19 +122,40 @@ public function hasCast(): bool return true; } - private function checkSqliteVersion(): bool + /* leave until alternative method fully tested */ + // private function checkSqliteVersion(): bool + // { + // /** @var PDOConnection */ + // $wrapped = $this->connection->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) && + // (version_compare(PHP_VERSION, self::PHP_WITH_SQLITE_JSON_SUPPORT) > 0); + //} + + private function hasSQLiteJSONSupport(): bool { - /** @var PDOConnection $wrapped */ - $wrapped = $this->connection->getWrappedConnection(); + // Here we can test SQLite for JSON support + // This should also work for MySQL + // For PostgreSQL a different query is required, but this should be easy to expand (check for driver + adjust query) + // Query = "SELECT JSON_EXTRACT('{"jsonfunctionalitytest":["succes"]}', '$.jsonfunctionalitytest') as value"; + // Should return value ["succes"], and throw an error if JSON unsupported. - // If the wrapper doesn't have `getAttribute`, we bail… - if (! method_exists($wrapped, 'getAttribute')) { + try { + $query = $this->connection->createQueryBuilder(); + $query + ->select('JSON_EXTRACT(\'{"jsonfunctionalitytest":["succes"]}\', \'$.jsonfunctionalitytest\') as value'); + $query->execute(); + } catch (\Throwable $e) { return false; } - [$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); + return true; } } From 39490e46d072b8c1301cb9e49d2415e8a9414c0c Mon Sep 17 00:00:00 2001 From: Wytse Talsma Date: Tue, 6 Oct 2020 22:19:17 +0200 Subject: [PATCH 20/23] cleanup --- .../src/Analysers/PlatformAnalyser.php | 58 ------------------- .../Interfaces/PlatformAnalyserInterface.php | 27 --------- 2 files changed, 85 deletions(-) delete mode 100644 vendor/vaimo/webdriver-binary-downloader/src/Analysers/PlatformAnalyser.php delete mode 100644 vendor/vaimo/webdriver-binary-downloader/src/Interfaces/PlatformAnalyserInterface.php diff --git a/vendor/vaimo/webdriver-binary-downloader/src/Analysers/PlatformAnalyser.php b/vendor/vaimo/webdriver-binary-downloader/src/Analysers/PlatformAnalyser.php deleted file mode 100644 index 02a8c6904..000000000 --- a/vendor/vaimo/webdriver-binary-downloader/src/Analysers/PlatformAnalyser.php +++ /dev/null @@ -1,58 +0,0 @@ - 'Linux 32Bits', - self::TYPE_LINUX64 => 'Linux 64Bits', - self::TYPE_MAC64 => 'Mac OS X', - self::TYPE_WIN32 => 'Windows 32Bits', - self::TYPE_WIN64 => 'Windows 64Bits', - self::TYPE_FREEBSD64 => 'FreeBSD 64Bits', - self::TYPE_FREEBSD32 => 'FreeBSD 32Bits', - ); - - return $names[$this->getPlatformCode()]; - } -} diff --git a/vendor/vaimo/webdriver-binary-downloader/src/Interfaces/PlatformAnalyserInterface.php b/vendor/vaimo/webdriver-binary-downloader/src/Interfaces/PlatformAnalyserInterface.php deleted file mode 100644 index b22944cd1..000000000 --- a/vendor/vaimo/webdriver-binary-downloader/src/Interfaces/PlatformAnalyserInterface.php +++ /dev/null @@ -1,27 +0,0 @@ - Date: Tue, 6 Oct 2020 22:26:42 +0200 Subject: [PATCH 21/23] Fix for returned bug: SQLSTATE[22P02]: Invalid text representation: 7 ERROR: invalid input syntax for integer: "a voluptas possimus aut libero doloremque."") in "helpers/_field_blocks.twig". --- templates/helpers/_field_blocks.twig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/templates/helpers/_field_blocks.twig b/templates/helpers/_field_blocks.twig index 946dea8ec..4cc308340 100644 --- a/templates/helpers/_field_blocks.twig +++ b/templates/helpers/_field_blocks.twig @@ -50,7 +50,7 @@

      {{ field|label }}:

        {% if field.contentSelect %} - {% setcontent selected = field.contentType where {'id': field.selectedIds} returnmultiple %} + {% setcontent selected = field.contentType where {'value': field.selectedIds} returnmultiple %} {% for record in selected %}
      • {{ record|title }}
      • {% endfor %} From 0ec56d4d38e332ec6d45bf67d3e5b600f1f96be7 Mon Sep 17 00:00:00 2001 From: Bob den Otter Date: Wed, 7 Oct 2020 14:05:18 +0200 Subject: [PATCH 22/23] Don't overwrite `$searchTerm` --- src/Repository/ContentRepository.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/Repository/ContentRepository.php b/src/Repository/ContentRepository.php index 55896b393..5820a8261 100644 --- a/src/Repository/ContentRepository.php +++ b/src/Repository/ContentRepository.php @@ -6,6 +6,7 @@ use Bolt\Configuration\Content\ContentType; use Bolt\Doctrine\JsonHelper; +use Bolt\Doctrine\Version; use Bolt\Entity\Content; use Bolt\Enum\Statuses; use Doctrine\Bundle\DoctrineBundle\Repository\ServiceEntityRepository; @@ -96,7 +97,7 @@ public function searchNaive(string $searchTerm, int $page, int $amountPerPage, C // proper JSON wrapping solves a lot of problems (added PostgreSQL compatibility) $connection = $qb->getEntityManager()->getConnection(); - [$where, $searchTerm] = JsonHelper::wrapJsonFunction('t.value', $searchTerm, $connection); + [$where] = JsonHelper::wrapJsonFunction('t.value', $searchTerm, $connection); $qb->addSelect('f') ->innerJoin('content.fields', 'f') From 0d0f50d3f11e344e1539102503f74a7f6f977282 Mon Sep 17 00:00:00 2001 From: Bob den Otter Date: Wed, 7 Oct 2020 14:05:59 +0200 Subject: [PATCH 23/23] Don't use `Bolt\Doctrine\Version` --- src/Repository/ContentRepository.php | 1 - 1 file changed, 1 deletion(-) diff --git a/src/Repository/ContentRepository.php b/src/Repository/ContentRepository.php index 5820a8261..3ef5ca72a 100644 --- a/src/Repository/ContentRepository.php +++ b/src/Repository/ContentRepository.php @@ -6,7 +6,6 @@ use Bolt\Configuration\Content\ContentType; use Bolt\Doctrine\JsonHelper; -use Bolt\Doctrine\Version; use Bolt\Entity\Content; use Bolt\Enum\Statuses; use Doctrine\Bundle\DoctrineBundle\Repository\ServiceEntityRepository;