Я решил свою собственную проблему с помощью этой записи .
По сути, DQL содержит NULLIF()
, а также COALESCE()
, но НЕ содержит CAST()
.Я добавил следующие классы:
<?php
namespace DoctrineFunctions;
use Doctrine\ORM\Query\AST\Functions\FunctionNode;
use Doctrine\ORM\Query\Lexer;
use Doctrine\ORM\Query\Parser;
use Doctrine\ORM\Query\SqlWalker;
class CastToBoolean extends FunctionNode
{
public $stringPrimary;
public function getSql(SqlWalker $sqlWalker)
{
return 'CAST(' . $this->stringPrimary->dispatch($sqlWalker) . ' AS boolean)';
}
public function parse(Parser $parser)
{
$parser->match(Lexer::T_IDENTIFIER);
$parser->match(Lexer::T_OPEN_PARENTHESIS);
$this->stringPrimary = $parser->StringPrimary();
$parser->match(Lexer::T_CLOSE_PARENTHESIS);
}
}
А также эту очень похожую функцию приведения для приведения к целому числу:
<?php
namespace DoctrineFunctions;
use Doctrine\ORM\Query\AST\Functions\FunctionNode;
use Doctrine\ORM\Query\Lexer;
use Doctrine\ORM\Query\Parser;
use Doctrine\ORM\Query\SqlWalker;
class CastToInteger extends FunctionNode
{
public $stringPrimary;
public function getSql(SqlWalker $sqlWalker)
{
return 'CAST(' . $this->stringPrimary->dispatch($sqlWalker) . ' AS integer)';
}
public function parse(Parser $parser)
{
$parser->match(Lexer::T_IDENTIFIER);
$parser->match(Lexer::T_OPEN_PARENTHESIS);
$this->stringPrimary = $parser->StringPrimary();
$parser->match(Lexer::T_CLOSE_PARENTHESIS);
}
}
Затем я регистрирую эти методы в doctrine.yml:
orm:
auto_generate_proxy_classes: ""
default_entity_manager: default
entity_managers:
default:
connection: default
mappings:
RBundle: ~
ABundle: ~
result_cache_driver:
type: memcached
host: ''
port:
query_cache_driver:
type: memcached
host: ''
port:
metadata_cache_driver:
type: memcached
host: ''
port:
naming_strategy: doctrine.orm.naming_strategy.underscore
filters:
softdeleteable:
class:
enabled:
dql:
numeric_functions:
cast_to_int: DoctrineFunctions\CastToInteger
string_functions:
cast_to_boolean: DoctrineFunctions\CastToBoolean
И, наконец, я реконструирую SQL-запрос как DQL-запрос со всеми необходимыми методами:
if (isset($searchParams[self::PARAM_MINIMUM_RATING])) {
$qb
->andWhere('((r.editedRatingTreatmentEffectiveness + r.editedRatingAccommodationsAmenities + r.editedRatingMealsNutrition) / (COALESCE(NULLIF(cast_to_int(cast_to_boolean(r.editedRatingTreatmentEffectiveness)) + cast_to_int(cast_to_boolean(r.editedRatingAccommodationsAmenities)) + cast_to_int(cast_to_boolean(r.editedRatingMealsNutrition)), 0), 1))) >= :minimum_rating')
->setParameter('minimum_rating', $searchParams[self::PARAM_MINIMUM_RATING]);
}