OTOBANK Engineering Blog

オトバンクはコンテンツが大好きなエンジニアを募集しています!

2016年10月のどや会ごはん - おにぎり有名店「ぼんご」のおにぎり

こんにちは!デザイナーのぺろこです!
ここ数日で急に寒くなりましたが、皆さんいかがお過ごしでしょうか?

さて、オトバンク開発部では毎月末に「どや会」を実施しています。

ビール片手に開催するこの会は、開発したものを"ドヤァ"したり、メンバー個人の近況を報告し合ったりして、チームビルディングに役立てようというものなのですが、参加者の感想としては「ご飯がおいしい」が9割なのではないかという噂もあります。

「どや会」の詳細についてはこちら engineering.otobank.co.jp

10月のどや会ごはん

おにぎり好きなら知っているという、おにぎり有名店「ぼんご」のおにぎりでした! www.hotpepper.jp

おにぎりを選ぶオトバンクの人々(真剣)

これまでは勝手にメニューを決めていたのですが、
今回はメンバーにそれぞれ食べたいおにぎりを選んでもらう形にしてみました。

f:id:peroko_tokyo:20161101193758p:plain
みんな吟味して選んでくれました!楽しげ!

f:id:peroko_tokyo:20161101185127p:plain:w400
他部署にも希望を募ったところ、予想以上に大盛り上がり!
弊社社長・会長からも熱いオーダーをいただきました。

f:id:peroko_tokyo:20161028205354p:plain
買ってきたおにぎりたち

おにぎりのお供はたまご焼き

人形町「鳥忠」「鳥近」の卵焼きを用意してみました。 一本丸ごとかぶりつきたくなる、東京の絶品卵焼き10選 | ランキングシェア byGMO

f:id:peroko_tokyo:20161101192536p:plain 老舗の料亭にも出しているそうです。どちらも好評でよかった!

しれっと#OnigiriActionもしましたw

ということで、みなさん、10月もおつかれさまでした〜!! 11月も頑張っていきましょ!

Symfony2のルーティングについて基礎的内容をまとめた

こんにちは。@mrtryです。 もう10月ですね。入社して半年か...。 残りの半年もがんばっていきたいと思います!

さて、「Symfony2入門」3回目の投稿です。 前回は、Symfony2での処理の流れについてまとめました。 今回は、その中で出てきた、ルーティングについて書きたいと思います。

以下、今回の目次になります。

  • ルーティングとは
  • ルーティングの設定方法
  • 設定されているルーティングの確認
  • ルーティングの設定例

ルーティングとは

ルーティングとは、リクエストされたURLに対して呼び出すアクションを決定する仕組みのことです。 例えば、/というパスにアクセスがあったらhomepageActionを実行する、というように対応付けする仕組みです。 Symfonyでは、ルーティングの設定次第で、対応付けを任意に設定することができます。

ルーティングの設定方法

ルーティングの設定は、YAML、XML、PHP、Annotationで設定できます。 今回の記事では、利用頻度が高いYAMLとAnnotationでの設定方法を紹介します。

YAML

Symfony2の設定ファイルは概ねYAMLで記述されています。 app/config以下を確認するだけでも、config.ymlparameters.ymlなどのYAMLファイルが確認できます。 ルーティングの設定も、YAMLファイルで設定されています。

YAMLについて馴染みがない方は、以下のページを読むと書き方を理解できるかと思います!

例によって、symfonyのデモアプリケーションを見てみます。 設定ファイルは、app/config/routing.ymlにあります。 以下の箇所の設定では、/というパスにアクセスがあった時、 default/homepage.html.twigを引数にとり、FrameworkBundleTemplateControllerにあるtemplateActionを実行するという設定が書かれています。 ルーティング名はhomepageとなっています。

homepage:
    path: /{_locale}
    requirements:
        _locale: '%app_locales%'
    defaults:
        _controller: FrameworkBundle:Template:template
        template:    default/homepage.html.twig
        _locale:     '%locale%'

Annotation

コントローラにAnnotationを書くことでルーティングの設定をすることもできます。 ベストプラクティス的には、Annotationを用いたルーティングの設定方法がオススメされています。

Annotationを利用するには、設定ファイルにAnnotationでルーティングするという設定をする必要があります。 例によって、symfonyのデモアプリケーションapp/config/routing.ymlを見てみます。 resourceでAnnotationが記述されているコントローラがあるディレクトリを指定し、typeAnnotationを設定します。

app/config/routing.yml

app:
    # @を先頭につけるとBundle以下からの相対パスで指定できます。
    resource: '@AppBundle/Controller/'
    type:     Annotation
    prefix:   /{_locale}
    requirements:
        _locale: '%app_locales%'
    defaults:
        _locale: '%locale%'

設定後、コントローラにてルーティングの設定を行うことができます。 /blog/blog/page/{page}にアクセスがあった時、このコントローラのindexAction()を呼び出すという設定がされています。 ルーティング名にはそれぞれ、blog_indexblog_index_paginatedとなっています。

src/AppBundle/Controller/BlogController.php

/**
* Controller used to manage blog contents in the public part of the site.
*
* @Route("/blog")
*
* @author Ryan Weaver <weaverryan@gmail.com>
* @author Javier Eguiluz <javier.eguiluz@gmail.com>
*/
class BlogController extends Controller
{
    /**
    * @Route("/", defaults={"page": 1}, name="blog_index")
    * @Route("/page/{page}", requirements={"page": "[1-9]\d*"}, name="blog_index_paginated")
    * @Method("GET")
    * @Cache(smaxage="10")
    */
    public function indexAction($page)
    {
       $posts = $this->getDoctrine()->getRepository(Post::class)->findLatest($page);

       return $this->render('blog/index.html.twig', ['posts' => $posts]);
    }

設定されているルーティングの確認

consoleでdebug:routeを実行すると、設定されているルーティングを確認することができます。 Nameを見ていくと、先ほど紹介したhomepageblog_indexblog_index_paginatedが確認できます。

$ bin/console debug:route

-------------------------- ---------- -------- ------ ----------------------------------------
Name                       Method     Scheme   Host   Path
-------------------------- ---------- -------- ------ ----------------------------------------
_wdt                       ANY        ANY      ANY    /_wdt/{token}
_profiler_home             ANY        ANY      ANY    /_profiler/
_profiler_search           ANY        ANY      ANY    /_profiler/search
_profiler_search_bar       ANY        ANY      ANY    /_profiler/search_bar
_profiler_info             ANY        ANY      ANY    /_profiler/info/{about}
_profiler_phpinfo          ANY        ANY      ANY    /_profiler/phpinfo
_profiler_search_results   ANY        ANY      ANY    /_profiler/{token}/search/results
_profiler                  ANY        ANY      ANY    /_profiler/{token}
_profiler_router           ANY        ANY      ANY    /_profiler/{token}/router
_profiler_exception        ANY        ANY      ANY    /_profiler/{token}/exception
_profiler_exception_css    ANY        ANY      ANY    /_profiler/{token}/exception.css
_twig_error_test           ANY        ANY      ANY    /{_locale}/_error/{code}.{_format}
admin_index                GET        ANY      ANY    /{_locale}/admin/post/
admin_post_index           GET        ANY      ANY    /{_locale}/admin/post/
admin_post_new             GET|POST   ANY      ANY    /{_locale}/admin/post/new
admin_post_show            GET        ANY      ANY    /{_locale}/admin/post/{id}
admin_post_edit            GET|POST   ANY      ANY    /{_locale}/admin/post/{id}/edit
admin_post_delete          DELETE     ANY      ANY    /{_locale}/admin/post/{id}
blog_index                 GET        ANY      ANY    /{_locale}/blog/
blog_index_paginated       GET        ANY      ANY    /{_locale}/blog/page/{page}
blog_post                  GET        ANY      ANY    /{_locale}/blog/posts/{slug}
comment_new                POST       ANY      ANY    /{_locale}/blog/comment/{postSlug}/new
security_login             ANY        ANY      ANY    /{_locale}/login
security_logout            ANY        ANY      ANY    /{_locale}/logout
homepage                   ANY        ANY      ANY    /{_locale}
-------------------------- ---------- -------- ------ ----------------------------------------

ルーティングの設定例

ルーティングの設定例を4パターン紹介します。

  • URLとコントローラを1対1で対応付け
  • ワイルドカードを利用した対応付け
  • 正規表現を利用した条件指定
  • HTTPメソッドの指定

それぞれのパターンで、YAMLとAnnotationの設定例を紹介します。 なお、Annotationでルーティング設定する際に必要なYAMLの設定は省略しています。

URLとコントローラを1対1で対応付け

URLとコントローラを1対1で対応付けする設定です。

以下の例では、/にアクセスがあったら、 AcmeDemoBundleMainControllerに定義されているhomepageAction()を呼び出す設定をしています。

YAML

YAMLで設定すると、以下のようになります。

_welcome:
    path:  /
    defaults:
        _controller: AcmeDemoBundle:Main:homepage

一番最初のkeyはルーティングに登録されるルート名です。 設定されたルート名はconsole debug:routeすると、Nameの欄に表示されます。 今回の設定だと、最初にkeyに_welcomeが設定されているので、これがそのままルート名になります。

ルート名以下は、ルーティングの設定になります。 マッチするパスの指定は、pathに設定します。 今回は、/にアクセスがあった際のルーティングを設定するので、path: /と書きます。

プレースホルダの初期値、特殊なルーティングパラメーターの設定する際には、defaults以下に書きます。 プレースホルダの初期値の設定については次の設定例で紹介し、この設定例では特殊なルーティングパラメーターの設定について紹介します。

特殊なルーティングパラメーター(Special Routing Parameter)とは、Symfonyで用意されている便利に使えるパラメータです。 _controller _format _locale の3種類がこれに該当します。

指定したパスで実行するコントローラを指定するには、特殊なルーティングパラメーターである_controller論理コントローラ名を設定します。 論理コントローラー名は、バンドル名:コントローラ名:アクション名という文字列で表現されます。

今回の場合、呼び出したいのはAcmeDemoBundleのMainControllerに定義されているhomepageAction()なので、 AcmeDemoBundle:Main:homepageが論理コントローラとなります。 注意点として、コントローラ名はController、アクション名はActionをそれぞれ省略する必要があるので、注意しましょう。

Annotation

同じ設定をAnnotationで設定すると、以下のようになります。

class MainController extends Controller
{
    /**
     * @Route("/", name="_welcome")
     */
    public function homepageAction()
    {
        ...
    }
}

Annotationでの設定は、Doucument Commentに@Route()というAnnotationを書くことで設定できます。 マッチするURLの指定は、( )内に書き、ルート名はname=""で指定をすることができます。 Annotationでルーティングを設定する際は、 _contorllerの指定は、Annotationを書いてあるコントローラが呼び出されるので、必要はありません。

ワイルドカードを利用した対応付け

/blog/1/blog/2/blog/3のようなパスにマッチするルーティングを設定しようとした時、 そのパスごとに設定を書いていたのでは、とても手間です。 内容が同じようなものを表示するのであれば、/blog/*というようにまとめて指定できたらとても便利です。 これは、/blog/{page}のようなプレースホルダを設定することで、マッチさせることができます。

以下の例では、 /blog/{page}というパスにアクセスがあった場合、AcmeBlogBundleBlogControllerindexAction()を実行する設定をしています。

YAML

YAMLで設定すると、以下のようになります。

blog_index:
    path:      /blog/{page}
    defaults:
        _controller:    AcmeBlogBundle:Blog:index
        page:           1

パスにプレースホルダを設定する際は、{プレースホルダ名}という書き方で設定できます。 今回の例では、pageという名前でプレースホルダを設定しています。

defaults以下では、プレースホルダの初期値を設定しています。 今回の例では、pageには初期値として1を設定しています。 この設定により、/blog/という感じにpageの箇所が空のパスにアクセスがあった場合、defaultsで指定した値が利用されpage = 1としてコントローラで処理が行われます。

また、設定したプレースホルダは、実行するコントローラの引数に設定することで、値をそのまま利用することができます。 例として、以下の様に書くことでメソッド内で値を利用できます。

public function indexAction($page)
{
    ...

    echo $page; // '/blog/{page}' のpageの値が返ってくる

    ...
}

Annotation

同じ設定をAnnotationで設定すると、以下のようになります。

    /**
     * @Route("/blog")
     *
     */
     class BlogController extends Controller
     {
        /**
         * @Route("/{page}", name="blog_index", defaults={"page": 1})
         *
         */
        public function indexAction($page)
        {
            ...
        }
    }

先ほどのAnnotationの設定と少し変わり、classに対しても@Route("/blog")と指定がされています。 こうすることで、class以下に定義されるURLに/blogというパスを付与することができます。 なので、indexAction()に設定されているURLは/{page}としか書かれていませんが、実際には/blog/{page}と一致します。

なお、YAMLではprefixを用いて設定することができます。

正規表現を利用した条件指定

/blog/{page}というように、まとめて指定する方法を紹介しました。 ですが、前回の設定だけだと、pageに対して値のチェックをしていないので、整数以外も取りうる可能性があります。 pageの値を正規表現でチェックし、整数のみに一致するルーティングの設定に修正します。

以下の例では、 /blog/{page}というURLにアクセスがあった場合、AcmeBlogBundleBlogControllerindexAction()を実行します。 ただし、pageの値は長さが1以上の整数、という制限を設定しています。

YAML

YAMLで設定すると、以下のようになります。

blog_index:
    path:      /blog/{page}
    defaults:
        _controller: AcmeBlogBundle:Blog:index
        page: 1
    requirements:
        page:  \d+

条件指定は、requirementsで指定し、ネストして定義してある変数名を挙げることで設定できます。 pageは整数にしぼりたいので、正規表現で長さが1以上の整数という指定をしています。

Annotation

同じ設定をAnnotationで設定すると、以下のようになります。

/**
 * @Route("/blog")
 *
 */
class BlogController extends Controller
{
    /**
     * @Route("/{page}", requirements={"page" = "\d+"}, name="blog_index",defaults={"page": 1})
     *
     */
    public function indexAction($page)
    {
        ...
    }
}

HTTPメソッドの指定

APIを実装した際などに、あるURLにアクセスするHTTPメソッドを指定したい時があります。 HTTPメソッドの指定も、ルーティングの設定で制限することができます。

以下の例では、/contactにアクセスがあった時

  • GETなら、AcmeDemoBundle:Main:contact
  • POSTなら、AcmeDemoBundle:Main:contactProcess

を呼び出すという設定をしています。

YAML

YAMLで設定すると、以下のようになります。

contact:
    path:     /contact
    defaults:
        _controller: AcmeDemoBundle:Main:contact
    methods:  [GET]

contact_process:
    path:     /contact
    defaults:
        _controller: AcmeDemoBundle:Main:contactProcess
    methods:  [POST]

HTTPメソッドを制限したいときは、methodsを用いて、配列でGETPOSTを指定することができます。

Annotation

同じ設定をAnnotationで設定すると、以下のようになります。

class MainController extends Controller
{
    /**
     * @Route("/contact", name="contact")
     * @Method("GET")
     *
     */
    public function contactAction()
    {
        ...
    }

    /**
     * @Route("/contact", name="contact_process")
     * @Method("POST")
     *
     */
    public function contactProcessAction()
    {
        ...
    }
}

@Method()というAnnotationを書くことで、メソッドの指定ができます。

おわりに

「Symfony2入門」の3回目として、ルーティングについて紹介しました。 次回は、コントローラについて基本的なことをまとめたいと思います。

参考

本番環境でもSymfony2のデバッグツールバー(Profiler)が見たい

ども。フジロックでは battles がベストアクトだと思っている @kalibora です。小ネタです。

Symfony2の開発時に下に出てくるアレ。すごい便利ですよね。

クリックすると↓こんな感じの画面になって

f:id:kalibora:20160920214502p:plain

DBへのクエリも確認できますし、簡易的にボトルネックがどこかも調べたりできます。

そんな便利なツールバー、本番環境でも見たいなーって時たまにありませんか?

基本的には開発環境だけで事足りるはずですけど、本番と開発環境でのデータ量の差だったりが影響して 本番環境でDBへのクエリがどうなってるのか確認したいとかとか。

とはいえ、本番環境でツールバーを表示するわけにはいきません。(セキュリティの問題とパフォーマンスの問題)

じゃあどうするか?それ用の環境を作ってしまいましょう。

幸い公式ドキュメントにそのようなときにぴったりな解説ページがあります。

これ → How to Master and Create new Environments (current)

でもですね、この通りにやってもツールバーが出ないのでちょっとだけ足してやる必要があります。

diffにすると以下のようになります。

diff --git a/app/AppKernel.php b/app/AppKernel.php
index 823d7a2..082e6fb 100644
--- a/app/AppKernel.php
+++ b/app/AppKernel.php
@@ -26,6 +26,10 @@ class AppKernel extends Kernel
             $bundles[] = new Doctrine\Bundle\FixturesBundle\DoctrineFixturesBundle();
         }

+        if (in_array($this->getEnvironment(), ['benchmark'], true)) {
+            $bundles[] = new Symfony\Bundle\WebProfilerBundle\WebProfilerBundle();
+        }
+
         return $bundles;
     }

diff --git a/app/config/config_benchmark.yml b/app/config/config_benchmark.yml
new file mode 100644
index 0000000..3a6892d
--- /dev/null
+++ b/app/config/config_benchmark.yml
@@ -0,0 +1,10 @@
+imports:
+    - { resource: config_prod.yml }
+
+framework:
+    profiler: { only_exceptions: false }
+    router:
+        resource: "%kernel.root_dir%/config/routing_benchmark.yml"
+
+web_profiler:
+    toolbar: true
diff --git a/app/config/routing_benchmark.yml b/app/config/routing_benchmark.yml
new file mode 100644
index 0000000..172205b
--- /dev/null
+++ b/app/config/routing_benchmark.yml
@@ -0,0 +1,10 @@
+_wdt:
+    resource: "@WebProfilerBundle/Resources/config/routing/wdt.xml"
+    prefix:   /_wdt
+
+_profiler:
+    resource: "@WebProfilerBundle/Resources/config/routing/profiler.xml"
+    prefix:   /_profiler
+
+_main:
+    resource: routing.yml
diff --git a/web/app_benchmark.php b/web/app_benchmark.php
new file mode 100644
index 0000000..8852777
--- /dev/null
+++ b/web/app_benchmark.php
@@ -0,0 +1,20 @@
+<?php
+
+use Symfony\Component\HttpFoundation\Request;
+
+/**
+ * @var Composer\Autoload\ClassLoader
+ */
+$loader = require __DIR__.'/../app/autoload.php';
+include_once __DIR__.'/../var/bootstrap.php.cache';
+
+$kernel = new AppKernel('benchmark', false);
+$kernel->loadClassCache();
+//$kernel = new AppCache($kernel);
+
+// When using the HttpCache, you need to call the method in your front controller instead of relying on the configuration parameter
+//Request::enableHttpMethodParameterOverride();
+$request = Request::createFromGlobals();
+$response = $kernel->handle($request);
+$response->send();
+$kernel->terminate($request, $response);

これで app_benchmark.php にアクセスすればツールバーが表示されます。

さぁ、っとここまでできたところでこれを実際に本番環境にデプロイして公開してしまってはセキュリティ的に問題なので、そこはお気をつけください。

きっと社内からしかアクセスできないようなステージング環境をみなさま用意していると思いますので、 そういうところだけにデプロイして使えば、 当初の目的だった本番環境(に限りなく近い環境)でデバッグツールバーが見れます。

それではみなさまごきげんよう。