LoginSignup
6
7

More than 5 years have passed since last update.

Symfony2: Doctrine で MySQL の FLOOR, ROUND などの数学関数を使用できるようにする

Last updated at Posted at 2013-02-26

当然のように 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 以外にも ROUNDCEIL, 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_mappingdoctrine.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_functionsstring_functions にしてあげれば ok。

仲間募集

Creema(クリーマ)では、一緒にサイト改善や業務改善をおこなってくれる Web エンジニアを募集しています。
Creema のエンジニアとして働きたい!という方は以下のリンクからご応募ください!
皆さまからのご応募、お待ちしております!

Web エンジニア採用ページ

参考記事

以上。 - 元記事

6
7
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
6
7