Edited at
SymfonyDay 17

Symfony初心者がつまづきがちな22個のポイント

この記事はSymfony Advent Calendar 2015 17日目の記事です。前日の記事は@teematsuさんの「Symfony 2.8とPHP-DIのAuto Wiring」でした。


こんにちは。はじめまして。tarokamikazeです。

すっかりSymfonyおじさんと化した私は、数々の後輩たちにSymfonyに関する相談を受けてきました。

そのなかでも、社内でよく聞かれることをまとめます。


導入編

The Symfony Book を読んだ人、ブログチュートリアルをやってみた人向けです。


01.この案件にSymfony2を使いたいんですが

下記のような条件では、Symfony2はおすすめです。


  • 専用サーバーを使える。

  • 他のPHP フレームワークを触ったことがある。

  • ビジネスロジックが複雑になりそうなシステムを作る。(業務アプリ等)

  • テストは当然書く。 1

  • プログラミング技術を磨きたい。

  • PHPのゆるふわさに嫌気が差してきた。2

  • (特に学習初期は)開発速度を犠牲にできる。ある程度学習コストを許容できる。

  • ドメイン駆動設計に興味がある。


02.公式サイトどこ?

日本語サイト は情報が古いです。本家(英語) を見ましょう。

不満に思う人は、翻訳作業に参加したらいいと思います。

以前参加したSymfony勉強会では

「Symfonyを使うくらいリテラシーのある人は、英語くらい読めるっしょwww」

と言っていました。恐ろしいですね。


03.日本語の本はありますか?

古いですが、「効率的なWebアプリケーションの作り方 ~PHPによるモダン開発入門 」しかなかったんですよ。書名にSymfonyって書いていないという罠。

しかし先日「基本からしっかり学ぶ Symfony2入門 」が出ました! いい時代ですね!


04.ここは読んどけって記事はありますか?

公式が充実してます。それを読めば、たいていのことは載っています。

Symfonyの歩き方/5分でわかるSymfony Best Practices はいい記事ですね。@ryo511 さん、ありがとうございます!


05.おすすめのバンドルは?


06.どのバージョンを使えばいいのでしょう?

ここを読んで考えましょう。Symfonyはサポート期間を明示してくれているので、利用バージョンを考えやすいですよね。

2015年12月現在、個人的には以下のように考えています。


  • 実案件なら、最新版LTSの 2.8

  • 勉強用なら、最新版の 3.0


07.公式の通りにインストールしたけど動かない

本当に公式の通りにインストールしたんですか? 本当に??

多くの人が、なぜかここ を読み飛ばします。

きちんとキャッシュ・ログディレクトリにパーミッションを設定しましょう。


  • Mac なら「2. Using ACL on a system that supports chmod +a」

  • CentOSなら「3. Using ACL on a system that does not support chmod +a」

  • Windowsなら、まずはMacを使わせてもらえるように上司(財布)と交渉しましょう。


    • 無理なら、VirtualBox に Linux を突っ込めばいいんじゃないでしょうかね。




08.フォルダ構成はどうしたらいいの?

Advent Calendarでちょうどいい記事が出ましたね。@issei-mさん、ありがとうございます!


09.設定は何で書けばいいの? XML?

Symfony Best Practicesによると、以下の様な感じです。


  • Routingは、アノテーション

  • DoctrineのEntity定義も、アノテーション

  • サービス設定はyaml 3


10.設定内容が反映されない><

キャッシュクリアしましょう。



php app/console cache:clear

それでもだめなら、apache(php-fpm)を再起動しましょう。

設定次第で、Symfony は app/cache だけではなく、APC(u) にもキャッシュをためます。


11.なんか英語のエラー出た><

まずは落ち着いて、エラーメッセージ読んでください。英語が苦手なら、Google翻訳に頼ってください。

それでもわからなければ、エラーメッセージでググってください。

利用者が多いフレームワークって、簡単なエラーでも記事が引っかかるのでいいですよね。


実装編

実案件で実装を始める人向けです。


12.Modelはどこに書くの?

「貴様の言うModelとは何だ? 」と訊くと、たいてい詰まりますよねw

Symfony2 は、(暗に)ドメイン駆動設計を推奨しています。 4


  • データを取り出したいなら、Repository

  • ビジネスロジックを記述したいなら、サービスを作ってDIコンテナに登録

という風に書けばよいでしょう。


13.確認フォームってどうやったら出せるの?

コツは、「Entity自体ではなく、Postされたarrayをセッションに詰めること」。

Doctrineは、Entity にメタデータを詰めます。このせいで、Entityをセッションに詰めると挙動がおかしくなります。(メタデータがserialize できません)

Formをからめるのであれば、POSTされたarrayをセッションに詰めましょう。

確認画面のAction ではセッションに詰めたarrayを、入力画面と同じFormType にbindしてあげればよいのです。


14.Ajax用の API 作りたい!

FOSRestBundle を使ってください。JMSSerializer便利だよぉ。

え、APIがちょっとしかないから、バンドルは導入したくない?しょうがないなぁ。

ここの通りにやればいいんじゃないのかなあ。

ちょっと古いけど、Symfony2 REST API: the best wayも目を通しておいた方がいいでしょう。


15.CSVダウンロード機能を作りたい!

最近のExcelは、XMLも読めますよ?(真顔) 5

冗談はさておき、こことか見たらいいんじゃないでしょうかね。


16.FormやAPIの形式とEntityの形がかけ離れている......つらい......

以下のようなやり方もあります。定義が散るので望ましくはないのですが。6


  1. Form / API の形に合わせたニセEntity(JavaBean的なモノ)をつくる。

  2. ニセEntity にあわせたFormType を用意し、リクエストデータはそれで受ける。

  3. ビジネスロジックに ニセEntity を 投げる。

  4. ビジネスロジック内でニセEntityを、本物のEntityに変換する。その後、永続化処理等を行う。

このときValidationは、form 側でやってもいいですし、変換後の本物EntityをValidatorサービスに投げてもいいでしょう。


17.ログインの仕組みを独自に作りたいんですけど......

悪いことは言わない。やめておけ。

Symfony2のログイン関係の仕組みは、複雑です。

可能な限りネイティブの仕組み、またはFOSUserBundleなどの外部バンドルにまかせたほうがいいです。

昔触ろうとして、一週間かかりました......


Doctrine編


18.Doctrineが不要なカラムもselectしようとしています。なんとかしたい。

ORM とはそういうものです。DBを富豪的に使うのです。

それでも重いというのなら、札束を積んで物理で殴ればよいのです。


19.Lazy Load うざい

デバッグコンソールを見ると、大量のSQLを吐いているときがあります。

原因としては、Doctrine で Entityに OneToMany を設定していると

「親も子も使うことがわかりきっているのに、子供にアクセスしたときにlazy load されて大量のSQLが走ってる」

というケースが多いです。

こういう場合は、DQLをしっかり書きましょう。

DQLでjoinすれば、一発で取ってきてくれます。


ParentRepository.php


class ParentRepository extends EntityRepository
{
public function findOneWithChild($parentId)
{
$qb = $this->createQueryBuilder('p');
$qb->select('p, c') // selectにもjoin先のaliasを書くのがコツ
->join('p.children', 'c')
->andWhere('p.id = :parentId')
->setParameter(':parentId', $parentId);
return $qb->getQuery()->getSingleResult();
}
}


20.論理削除ってどうすればいいの?

まずはここ を読め。話はそれからだ。

StofDoctrineExtensionsBundleSoftdeleteable を使います。

削除日時のカラムがNot Null だったら、削除とみなされます。


21. OneToMany を設定していて、親のEntityと子供のEntityを一気にpersistしようとしたらエラーが出た

こういう単純な例って、なかなか見つからないんですよね。7


test.php

$em = $this->get('doctrine.orm.entity_manager');

$parentEntity = new ParentEntity();
$childEntity = new ChildEntity();
$childEntity->setParent($parentEntity);

$em->persist($parentEntity);
$em->persist($childEntity);

$em->flush();



22.「Update時に、自動的にあのカラムも更新する」とかやりたい。EventLister を使えばいいの?

悪いことは言わない。やめておけ。

頼むから、更新対象のEntityをビジネスロジッククラスに渡して処理するんだ。

この面倒臭さを説明しだすと、ひとつの記事になってしまいます。

とりあえず Doctrineのこのクラス を読んでみてください。理由がわかってもらえるはずです。

ちなみに、更新日時を入れたいだけだったら

StofDoctrineExtensionsBundleTimestampable を使いましょう。


ちなみに22個である理由は、妻が猫好きだからです。

明日は@naoyes さんです!






  1. Symfony2はテストが書きやすいと言われています。 



  2. 自然とJavaっぽいコードになります。Java の Spring Framework に似ていると言われています。 



  3. JMSDiExtraBundleを使えば、サービスもアノテーションで定義できます。 



  4. そういった意味では、Symfonyは単なる「MVC」フレームワークではない何かです。以前参加したSymfony勉強会でも、ドメイン駆動設計の話題でもちきりでした。 



  5. 筆者はExcelとCSVを憎んでいます。エンジニアになる前は、Excel職人(運用のひと)でした。 



  6. 実例をGithubにあげたい。だが時間がない...... 



  7. Cascade persist する手もありますが、おすすめされていません。