当然のように FLOOR
関数が使えると思ってた。
$qb = $this->getDoctrine()
->getRepository('MyBundle:Test')
->createQueryBuilder('test')
->select('COUNT(test.id) AS rows')
->addSelect('FLOOR(test.hoge / test.fuga) AS rate');
~~
~~
~~
$result = $qb->getQuery()->getResult();
Symfony2 で上記のような DQL を書いて実行したときに、こんなエラーがでた。
QueryException: [Syntax Error] line {LINE}, col {COL}: Error: Expected known function, got 'FLOOR'
in /path/to/vendor/doctrine/orm/lib/Doctrine/ORM/Query/QueryException.php at line 44
「え!デフォルトで FLOOR 使えないの!?」と思ってしまった。
FLOOR
以外にも ROUND
も CEIL
, TRUNCATE
... ABS
なども使えない。(MySQL 数学関数)
それではどうしたら使えるようになるのか。
ここ(14.5.5. Adding your own functions to the DQL language)に答えが載ってた。
FLOOR
が使いたい場合、以下のようなコードをバンドル以下に配置する。
(各バンドルで作るよりかは、Doctrine 拡張用の汎用バンドルのほうが便利かなー、と思った。)
// MyBundle/Query/AST/MysqlFloor.php
<?php
namespace MyBundle\Query\AST;
use \Doctrine\ORM\Query\AST\Functions\FunctionNode;
use \Doctrine\ORM\Query\Lexer;
class MysqlFloor extends FunctionNode
{
public $simpleArithmeticExpression;
public function getSql(\Doctrine\ORM\Query\SqlWalker $sqlWalker)
{
return 'FLOOR(' . $sqlWalker->walkSimpleArithmeticExpression(
$this->simpleArithmeticExpression
) . ')';
}
public function parse(\Doctrine\ORM\Query\Parser $parser)
{
$lexer = $parser->getLexer();
$parser->match(Lexer::T_IDENTIFIER);
$parser->match(Lexer::T_OPEN_PARENTHESIS);
$this->simpleArithmeticExpression = $parser->SimpleArithmeticExpression();
$parser->match(Lexer::T_CLOSE_PARENTHESIS);
}
}
次に FLOOR
関数を Doctrine に教えるわけだが、このやり方よりも設定ファイルで教えたかったので、config.yml
を使うやり方にする。
config.yml
で設定する場合、以下が現状の doctrine
関係の設定箇所だとすると、
// app/config/config.yml
# Doctrine Configuration
doctrine:
dbal:
~~~~
~~~~
orm:
auto_generate_proxy_classes: %kernel.debug%
auto_mapping: true
doctrine.orm
を以下のように変更する必要がある。
// app/config/config.yml
# Doctrine Configuration
doctrine:
dbal:
~~~~
~~~~
orm:
auto_generate_proxy_classes: %kernel.debug%
auto_mapping: true
entity_managers:
default:
dql:
numeric_functions:
FLOOR: MyBundle\Query\AST\MysqlFloor
しかしながら、これではまたもやエラーが発生してしまう。
InvalidConfigurationException: Unrecognized options "auto_mapping" under "doctrine.orm"
in /path/to/vendor/symfony/symfony/src/Symfony/Component/Config/Definition/ArrayNode.php line 278
doctrine.orm.auto_mapping
を doctrine.orm.entity_managers.default
に配置しなければいけないらしい。
// app/config/config.yml
# Doctrine Configuration
doctrine:
dbal:
~~~~
~~~~
orm:
auto_generate_proxy_classes: %kernel.debug%
entity_managers:
default:
auto_mapping: true
dql:
numeric_functions:
FLOOR: MyBundle\Query\AST\MysqlFloor
これで FLOOR
関数が使える。
もし数学関数以外で有効になっていない関数などがあるならば、これまでと同じやり方で有効にできる。
文字列関数なら numeric_functions
を string_functions
にしてあげれば ok。
仲間募集
Creema(クリーマ)では、一緒にサイト改善や業務改善をおこなってくれる Web エンジニアを募集しています。
Creema のエンジニアとして働きたい!という方は以下のリンクからご応募ください!
皆さまからのご応募、お待ちしております!
参考記事
- doctrine2/lib/Doctrine/ORM/Query/Parser.php at master - doctrine/doctrine2 - GitHub
- InvalidConfigurationException: Unrecognized options "auto_mapping" under "doctrine.orm" - Issue #141 - stof/StofDoctrineExtensionsBundle
- How use DoctrineExtensions in Symfony2? - Issue #70 - beberlei/DoctrineExtensions
- 14. Doctrine Query Language - Doctrine 2 ORM 2.2 documentation
- MySQL :: MySQL 5.6 Reference Manual :: 12.6.2 Mathematical Functions
以上。 - 元記事