Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions config/packages/doctrine.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -33,3 +33,5 @@ doctrine:
string_functions:
JSON_EXTRACT: Bolt\Doctrine\Functions\JsonExtract
JSON_CONTAINS: Scienta\DoctrineJsonFunctions\Query\AST\Functions\Mysql\JsonContains
numeric_functions:
RAND: Bolt\Doctrine\Functions\Rand
38 changes: 38 additions & 0 deletions src/Doctrine/Functions/Rand.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
<?php

declare(strict_types=1);

namespace Bolt\Doctrine\Functions;

use Doctrine\ORM\Query\AST\Functions\FunctionNode;
use Doctrine\ORM\Query\AST\SimpleArithmeticExpression;
use Doctrine\ORM\Query\Lexer;

class Rand extends FunctionNode
{
/** @var SimpleArithmeticExpression */
private $expression = null;

public function getSql(\Doctrine\ORM\Query\SqlWalker $sqlWalker)
{
// value is one if SQLite. See Bolt\Storage\Directive\RandomDirectiveHandler
if (property_exists($this->expression, 'value') && $this->expression->value === '1') {
return 'random()';
}

return 'RAND()';
}

public function parse(\Doctrine\ORM\Query\Parser $parser): void
{
$lexer = $parser->getLexer();
$parser->match(Lexer::T_IDENTIFIER);
$parser->match(Lexer::T_OPEN_PARENTHESIS);

if ($lexer->lookahead['type'] !== Lexer::T_CLOSE_PARENTHESIS) {
$this->expression = $parser->SimpleArithmeticExpression();
}

$parser->match(Lexer::T_CLOSE_PARENTHESIS);
}
}
9 changes: 8 additions & 1 deletion src/Storage/ContentQueryParser.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
namespace Bolt\Storage;

use Bolt\Configuration\Config;
use Bolt\Doctrine\Version;
use Bolt\Entity\Content;
use Bolt\Repository\ContentRepository;
use Bolt\Storage\Directive\EarliestDirectiveHandler;
Expand All @@ -14,6 +15,7 @@
use Bolt\Storage\Directive\OffsetDirective;
use Bolt\Storage\Directive\OrderDirective;
use Bolt\Storage\Directive\PrintQueryDirective;
use Bolt\Storage\Directive\RandomDirectiveHandler;
use Bolt\Storage\Directive\ReturnMultipleDirective;
use Bolt\Storage\Directive\ReturnSingleDirective;
use Bolt\Storage\Handler\IdentifiedSelectHandler;
Expand Down Expand Up @@ -85,10 +87,13 @@ class ContentQueryParser
/** @var Notifications */
private $notifications;

/** @var Version */
private $version;

/**
* Constructor.
*/
public function __construct(RequestStack $requestStack, ContentRepository $repo, Config $config, LocaleHelper $localeHelper, Environment $twig, Notifications $notifications, ?QueryInterface $queryHandler = null)
public function __construct(RequestStack $requestStack, ContentRepository $repo, Config $config, LocaleHelper $localeHelper, Environment $twig, Notifications $notifications, Version $version, ?QueryInterface $queryHandler = null)
{
$this->repo = $repo;
$this->requestStack = $requestStack;
Expand All @@ -100,6 +105,7 @@ public function __construct(RequestStack $requestStack, ContentRepository $repo,
$this->localeHelper = $localeHelper;
$this->twig = $twig;
$this->notifications = $notifications;
$this->version = $version;

$this->setupDefaults();
$this->config = $config;
Expand All @@ -122,6 +128,7 @@ protected function setupDefaults(): void
$this->addDirectiveHandler(ReturnMultipleDirective::NAME, new ReturnMultipleDirective());
$this->addDirectiveHandler(LatestDirectiveHandler::NAME, new LatestDirectiveHandler());
$this->addDirectiveHandler(EarliestDirectiveHandler::NAME, new EarliestDirectiveHandler());
$this->addDirectiveHandler(RandomDirectiveHandler::NAME, new RandomDirectiveHandler($this->version));
}

/**
Expand Down
4 changes: 2 additions & 2 deletions src/Storage/Directive/EarliestDirectiveHandler.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,9 @@
use Bolt\Storage\QueryInterface;

/**
* Directive to modify query based on activation of 'latest' modifier.
* Directive to modify query based on activation of 'earliest' modifier.
*
* eg: {% setcontent pages = 'pages' first %}
* eg: {% setcontent pages = 'pages' earliest %}
*/
class EarliestDirectiveHandler
{
Expand Down
2 changes: 1 addition & 1 deletion src/Storage/Directive/OffsetDirective.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
use Bolt\Storage\SelectQuery;

/**
* Directive to add a limit modifier to the query.
* Directive to add a paging modifier to the query.
*/
class OffsetDirective
{
Expand Down
37 changes: 37 additions & 0 deletions src/Storage/Directive/RandomDirectiveHandler.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
<?php

declare(strict_types=1);

namespace Bolt\Storage\Directive;

use Bolt\Doctrine\Version;
use Bolt\Storage\QueryInterface;

/**
* Directive to modify query based on activation of 'random' modifier.
*
* eg: {% setcontent pages = 'pages' random %}
*/
class RandomDirectiveHandler
{
public const NAME = 'random';

/** @var Version */
private $version;

public function __construct(Version $version)
{
$this->version = $version;
}

public function __invoke(QueryInterface $query, $value, &$directives): void
{
if ($this->version->getPlatform()['driver_name'] === 'sqlite') {
$query->getQueryBuilder()->addSelect('RAND(1) as HIDDEN rand')->addOrderBy('rand');

return;
}

$query->getQueryBuilder()->addSelect('RAND(0) as HIDDEN rand')->addOrderBy('rand');
}
}
12 changes: 11 additions & 1 deletion src/Twig/TokenParser/SetcontentTokenParser.php
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
use Bolt\Storage\Directive\OffsetDirective;
use Bolt\Storage\Directive\OrderDirective;
use Bolt\Storage\Directive\PrintQueryDirective;
use Bolt\Storage\Directive\RandomDirectiveHandler;
use Bolt\Storage\Directive\ReturnMultipleDirective;
use Bolt\Storage\Directive\ReturnSingleDirective;
use Bolt\Twig\Node\SetcontentNode;
Expand Down Expand Up @@ -120,7 +121,7 @@ public function parse(Token $token): Node
);
}

// first parameter
// earliest parameter
if ($this->parser->getStream()->test(Token::NAME_TYPE, EarliestDirectiveHandler::NAME)) {
$this->parser->getStream()->next();
$arguments->addElement(
Expand All @@ -129,6 +130,15 @@ public function parse(Token $token): Node
);
}

// random parameter
if ($this->parser->getStream()->test(Token::NAME_TYPE, RandomDirectiveHandler::NAME)) {
$this->parser->getStream()->next();
$arguments->addElement(
new ConstantExpression(true, $lineno),
new ConstantExpression(RandomDirectiveHandler::NAME, $lineno)
);
}

// Make sure we don't get stuck in a loop, if a token can't be parsed.
++$counter;
} while (! $this->parser->getStream()->test(Token::BLOCK_END_TYPE) && ($counter < 10));
Expand Down