[twig] twigで再帰呼び出し

twigで再帰呼び出しができると知りました
そのような処理が必要なときはできるだけPHPで前処理してテンプレートに渡すようにしてましたが、twigで処理できるならそのほうがスマートな場合も多そうです

きっかけはECCUBE4のソース
カテゴリを表示している場所で再帰呼び出しをしています

src/Eccube/Resource/template/default/Block/category_nav_pc.twig

{% set Categories = repository('Eccube\\Entity\\Category').getList() %}

{% macro tree(Category) %}
    {% from _self import tree %}
    <a href="{{ url('product_list') }}?category_id={{ Category.id }}">
        {{ Category.name }}
    </a>
    {% if Category.children|length > 0 %}
        <ul>
            {% for ChildCategory in Category.children %}
                <li>
                    {{ tree(ChildCategory) }}
                </li>
            {% endfor %}
        </ul>
    {% endif %}
{% endmacro %}

{# @see https://github.com/bolt/bolt/pull/2388 #}
{% from _self import tree %}

<div class="ec-categoryNaviRole">
    <div class="ec-itemNav">
        <ul class="ec-itemNav__nav">
            {% for Category in Categories %}
                <li>
                    {{ tree(Category) }}
                </li>
            {% endfor %}
        </ul>
    </div>
</div>

上記のソースでは前半部分でmacroを定義して、後半でそれを一回呼び出してます
呼びされたmacroの中でさらにまた自分自身を呼び出すことで、カテゴリの深さのぶんだけ再帰的に処理されるようになっています

[PHP] calcurate UPC-E check digit

最近バーコード絡みの案件があるのでちょくちょくバーコードネタが出てきます
今日はUPC-E(8桁短縮タイプ)のチェックデジットを計算する関数を作ってみました

そんなライブラリどこかに転がってるだろ、と思っていたのですが、これが意外に見つからない・・・
UPC-A対応ならあるのですが、8桁短縮コードは考慮されていない事が多かったです
探し方が悪かったのかな?
とにかく、見つけられなかった以上、自作します

基本的にはJAN(=EAN)であろうとUPCであろうとModulus10/Weight3と呼ばれる方法でチェックデジットは計算されています
これはざっくり言うと、奇数桁の合計×3 + 偶数桁の合計 を10で割った余りを10から引いたもの、です

日本語で書くよりソースコードのほうがわかりやすそうです

function calc_checkdigit($code)
{
    if( !ctype_digit($code) ) return false;
    $code = (string)$code;
    $odd_total  = 0;
    $even_total = 0;
    
    for($i=0; $i<strlen($code); $i++)
    {
        if((($i+1)%2) == 0) {
            // 偶数行合計
            $even_total += $code[$i];
        } else {
            // 奇数行合計
            $odd_total += $code[$i];
        }
    }
 
    // 奇数桁の合計×3 + 偶数桁の合計
    $sum = (3*$odd_total) + $even_total;
    // 10で割った余りを求める
    $remainder = $sum%10;
    // 求められた余りを10から引いた値がチェックデジット(10の場合は0)
    return( (10-$remainder)%10 );
}

で、問題はここから

UPC-Eの場合は一度UPC-A(12桁の通常タイプ)に変換してから計算するという仕様なのですが、この変換がちょっとややこしい
UPC-Eの8桁のうち先頭の1桁は0で固定されており、また末尾1桁はチェックデジットなので、意味のある文字列は2桁目から7桁目までの6文字になるのですが、その末尾(全体の7桁目)によって変換の方法が変わるという仕様です

まとめた資料がcanonさんにありました
UPC短縮バーコードチェックデジット計算方法

よく見るとそこまで複雑な話ではないのですが、ぱっと見じゃ理解できないですよね…

PHPで処理を書くとこうなります

function upce2upca($code)
{
    if( !ctype_digit($code) ) return false;
    $code = (string)$code;
    $len = strlen($code);
    if( $len != 7) return false;
    
    switch($code[6])
    {
        case '0':
        case '1':
        case '2':
            $ret = substr($code,0,3).$code[6].'0000'.substr($code,3,3);
            break;
        case '3':
            $ret = substr($code,0,4).'00000'.substr($code,4,2);
            break;
        case '4':
            $ret = substr($code,0,5).'00000'.$code[5];
            break;
        default:
            $ret = substr($code,0,6).'0000'.$code[6];
            break;
    }
    return $ret;
}

さきほどのModulus10/Weight3の計算と合わせて使うことでUPC-Eのチェックデジット計算ができます

// チェックデジット計算前の7桁
$raw_upce = '0123456'; 

// UPC-A(チェックデジット加える前の11桁)に変換
$raw_upca = upce2upca($raw_upce );

// チェックデジットを計算
$cd = calc_checkdigit($raw_upca); // 5

// 有効な8桁UPC-Eを作る
$valid_upce = $raw_upce.$cd; // 01234565

[PHP] PDFlibでImage_Barcode2で作ったJANのバーコードを貼り付ける

昨日の続きです。

Image_Barcode2で作ったバーコードをPDFに貼り付けたい。
この案件ではPDF作成にPDFlibを使っています。

// $this->pdflib はPDFlibオブジェクト

protected function pdf_set_barcode($jancode, $x, $y, $opt='')
{
    $barcode_height = 30;
    $barcode_width = 1;
    $barcode_with_num = true;
    $pvf_filename = $jancode;
    
    ob_start(); 
    $gd = Image_Barcode2::draw($jancode, 'ean13', 'png', false, $barcode_height, $barcode_width, $barcode_with_num);
    imagepng($gd, null);
    imagedestroy($gd);
    $this->pdflib->create_pvf($pvf_filename, ob_get_clean(), "");
    $barcode_image = $this->pdflib->load_image('png', $pvf_filename, '');
    $this->pdflib->fit_image($barcode_image, $x, $y, $opt);
    $this->pdflib->close_image($barcode_image);
    $this->pdflib->delete_pvf($pvf_filename);
}

load_imageがファイルを要求しているんだけどいちいちtmpファイル保存するのもなんか気持ち悪いな、って思っていたところ、pvf(PDFlib Virtual file)というのがあったのでそれを使っています。

GDの出力データをob_使わずに取得する方法ないのかな…

[PHP] JANコードをバーコード表示するためにcomposer経由でImage_Barcode2をインストールする

PDF上でJANコードをバーコードを表示したいという案件がありました。
バーコードfontというものがあるようだけど、JANコード=EAN13コードの場合コード変換などが必要でめんどくさそう。
それよりもImage_Barcode2で画像として作っちゃうのが良さそうだったので、これを採用することにしました。
composerを使っている環境だったのでそちらを使ってインストールします。

$ php composer.phar require pear/image_barcode2:dev-master

stableがないということで:dev-masterを付けないとだめだよっていうのが今回のTIPS

続きがあります