ミリサイズ

頭の中をコピー・ペースト

Eloquentを使いこなせないと思ったらTwigが使いこなせてなかった話

こんばんは。

昨日、こんな記事を書きました。

LaravelのEloquentを使いこなせない話 - ミリサイズ

「Eloquentを使いこなせない話」と書いてましたが、実はTwigを使いこなせてなかった話だったので、お詫び訂正と"こうやったら解決しました!"ということを書いておこうと思います。

ごく初歩的なミスだったのでお恥ずかしく地面に埋まりたい限りです。

Twigの配列(またはコレクションオブジェクト)の扱い方

Eloquentから取得したデータは前回と同じです。 もう一度載せると、下記のような感じです。 (厳密には、arrayではなくコレクションオブジェクトですが、Twig上での扱いは変わらないようなのでこんな構造だよということで簡易的に書いてます)

array[0]{
 ["id"] => 123456
 ["screen_name"] => "8みり"
 ["screen_id"] => "8miri"
 ["prof_image_url"] => "http:xxx.png"
 ["sheets"] =>
   array[0]{
    ["id"] => 1
    ["event_id"] => 1
    ["user_id"] => 123456
    ["type"] => "アリーナ"
   }
 } 

これをTwigにusersという名前で渡して、sheetsの中身を表示しようとした場合、

{% for user in users %}
UserID:{{user.id}}<br>ScreenID:{{user.screen_id}}<BR>Type:{{user.sheets.type}}
{% endfor %}

だとうまくいかない!という状況でした。

昨日は行き詰まり感もあり諦めたのですが、今日になり、リフレッシュした頭でよくよく考えてみると、ん?これでうまくいかないのは当たり前な気がしてきたぞ、と。

で、書きなおしたのがこれです。

{% for user in users %}
    {% for sheet in user.sheets %}
        UserID:{{user.id}}<br>ScreenID:{{user.screen_id}}<br>Type:{{sheet.type}}<br>
    {% endfor %}
{% endfor %}

で、表示させてみると、、、

UserID:123456
ScreenID:8miri
Type:アリーナ

キタ!

あっさりできちゃいました。

見落としていたのは、Twigのforを使った配列アクセスがどうなっているのかという点でした。

Twigの処理はこうなっていた

Twigに渡したコレクションオブジェクトがどうなっていたか?を思い出してみましょう。

array[0]{
 ["id"] => 123456
 ["screen_name"] => "8みり"
 ["screen_id"] => "8miri"
 ["prof_image_url"] => "http:xxx.png"
 ["sheets"] =>
   array[0]{
    ["id"] => 1
    ["event_id"] => 1
    ["user_id"] => 123456
    ["type"] => "アリーナ"
   }
 } 

こうなっていますね。

そして、Twigにはusersという名前で渡しているので、例えば"screen_name"を取り出すには、users.0.screen_nameでアクセスする必要があります。

ん?でもそういう書き方してないよな?
・・・アッー!

{% for user in users %}
UserID:{{user.id}}<br>ScreenID:{{user.screen_id}}<BR>Type:{{user.sheets.type}}
{% endfor %}

そう、forを使っていたのでした。

Twigのfor文は、例えば上の書き方だと"usersの[n]番目の要素(users.n)を先頭から最終まで一個ずつ取り出して、userに突っ込んで、繰り返し中身を処理するよ"ということです。foreachと同じです。

なので、forの中で使っている"user"には一回目は"users.0"が渡されているわけです。 (わかると思いますが、二回目は"users.1"が渡されます。要素があれば。)

つまり、このforの中で1回目の'user.sheets.type'は'users.0.sheets.type'という呼び出しをしていることと同義になります。

ここで、Twigに渡したコレクションオブジェクトの構成(sheetsの中だけ)をもう一度振り返ってみましょう。

 ["sheets"] =>
   array[0]{
    ["id"] => 1
    ["event_id"] => 1
    ["user_id"] => 123456
    ["type"] => "アリーナ"
 } 

うん、sheets.0.typeってやらないとダメじゃん、これ。

で、一人のユーザーに対してsheetsが複数とれた場合はこうするよな、ということで書き換えたのがさっきのこれです。

{% for user in users %}
    {% for sheet in user.sheets %}
        UserID:{{user.id}}<br>ScreenID:{{user.screen_id}}<br>Type:{{sheet.type}}<br>
    {% endfor %}
{% endfor %}

入れ子になっている{% for sheet in user.sheets %}で、sheetにuser.sheets.nを毎回渡しているので、sheet.typeuser.sheets.n.typeと同義なので、うまく取得できます、ということになります。

なぜこんなことに気付かなかったのだろう・・・という感じですが、とりあえず思い通りの出力ができるようになったので良かったです!

TwigとEloquentにごめんなさいm( )m