0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

【EC-CUBE4.3】全角カタカナでLIKE検索すると半角カタカナの濁点・半濁点がヒットしない

Last updated at Posted at 2025-04-09

はじめに

保守しているECサイトで、商品検索の際に全角カタカナで検索すると、半角カタカナの商品が引っかからないという要望があった。(その逆も然り)

ググってみると、参考になる記事があったためそちらを参考にChatGPTの力を借りて修正してみる。
参考サイト:https://dodosu.hatenablog.jp/entry/2021/01/26/125325

とりあえずやってみる

とりあえず、

SELECT * FROM skill WHERE(REPLACE(REPLACE(bigName, '゙', ''), '゚', '') collate utf8_unicode_ci LIKE REPLACE(REPLACE(?0, '゙', ''), '゚', ''))

のようなことは、できるのかと聞いてみるとDoctrineでは、REPLACEは標準では使えないよう。

カスタムDQL関数なるものを定義すればできるとのことで指示に従ってやってみる。

1. app/Customize/Doctrine/ORM/Query/Replace.php を作成

namespace Customize\Doctrine\ORM\Query;

use Doctrine\ORM\Query\Lexer;
use Doctrine\ORM\Query\AST\Functions\FunctionNode;
use Doctrine\ORM\Query\Parser;
use Doctrine\ORM\Query\SqlWalker;

class Replace extends FunctionNode
{
    public $stringPrimary;
    public $stringFrom;
    public $stringTo;

    public function parse(Parser $parser)
    {
        $parser->match(Lexer::T_IDENTIFIER);     // REPLACE
        $parser->match(Lexer::T_OPEN_PARENTHESIS); // (
        $this->stringPrimary = $parser->StringPrimary();
        $parser->match(Lexer::T_COMMA);           // ,
        $this->stringFrom = $parser->StringPrimary();
        $parser->match(Lexer::T_COMMA);           // ,
        $this->stringTo = $parser->StringPrimary();
        $parser->match(Lexer::T_CLOSE_PARENTHESIS); // )
    }

    public function getSql(SqlWalker $sqlWalker)
    {
        return sprintf(
            'REPLACE(%s, %s, %s)',
            $this->stringPrimary->dispatch($sqlWalker),
            $this->stringFrom->dispatch($sqlWalker),
            $this->stringTo->dispatch($sqlWalker)
        );
    }
}

ほぼ、ChatGPTが提案してくれたものそのまま。

2. doctrine.yaml にカスタムDQL関数なるものを登録

    orm:
        auto_generate_proxy_classes: '%kernel.debug%'
        naming_strategy: doctrine.orm.naming_strategy.underscore_number_aware
        auto_mapping: true
        dql:
            string_functions:
                NORMALIZE: Eccube\Doctrine\ORM\Query\Normalize
                REPLACE: Customize\Doctrine\ORM\Query\Replace # ←ここ
            numeric_functions:
                EXTRACT: Eccube\Doctrine\ORM\Query\Extract

3. 該当箇所のコードを修正

src/Eccube/Repository/ProductRepository.phpを編集する。
↑ここに、商品検索のクエリを作成しているメソッドがある。
※ 本来は、app/Customize配下に継承するなりして作る。

    public function getQueryBuilderBySearchData($searchData)
    {
        $qb = $this->createQueryBuilder('p')
            ->andWhere('p.Status = 1');

        // category
        $categoryJoin = false;
        if (!empty($searchData['category_id']) && $searchData['category_id']) {
            $Categories = $searchData['category_id']->getSelfAndDescendants();
            if ($Categories) {
                $qb
                    ->innerJoin('p.ProductCategories', 'pct')
                    ->innerJoin('pct.Category', 'c')
                    ->andWhere($qb->expr()->in('pct.Category', ':Categories'))
                    ->setParameter('Categories', $Categories);
                $categoryJoin = true;
            }
        }

        // name
        if (isset($searchData['name']) && StringUtil::isNotBlank($searchData['name'])) {
            $keywords = preg_split('/[\s ]+/u', str_replace(['%', '_'], ['\\%', '\\_'], $searchData['name']), -1, PREG_SPLIT_NO_EMPTY);

            foreach ($keywords as $index => $keyword) {
                $key = sprintf('keyword%s', $index);
                $qb
                    ->andWhere(sprintf( // ↓ココ
                        'REPLACE(REPLACE(NORMALIZE(p.name), \'゙\', \'\'), \'゚\', \'\') LIKE REPLACE(REPLACE(NORMALIZE(:%s), \'゙\', \'\'), \'゚\', \'\') OR
                        NORMALIZE(p.search_word) LIKE NORMALIZE(:%s) OR
                        EXISTS (SELECT wpc%d FROM \Eccube\Entity\ProductClass wpc%d WHERE p = wpc%d.Product AND NORMALIZE(wpc%d.code) LIKE NORMALIZE(:%s))',
                        $key,
                        $key,
                        $index,
                        $index,
                        $index,
                        $index,
                        $key
                    ))
                    ->setParameter($key, '%' . $keyword . '%');
            }
        }

これで、問題なく検索ができるようになった。
image.png

0
0
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
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?