この記事は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.おすすめのバンドルは?
- ユーザー/ログイン管理のFOSUserBundle
- マイグレーション(DBスキーマ差分管理)の DoctrineMigrationsBundle
- フィクスチャ(DBへのデータ投入)の DoctrineFixturesBundle
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
- Form / API の形に合わせたニセEntity(JavaBean的なモノ)をつくる。
- ニセEntity にあわせたFormType を用意し、リクエストデータはそれで受ける。
- ビジネスロジックに ニセEntity を 投げる。
- ビジネスロジック内でニセ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すれば、一発で取ってきてくれます。
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.論理削除ってどうすればいいの?
まずはここ を読め。話はそれからだ。
StofDoctrineExtensionsBundle の Softdeleteable を使います。
削除日時のカラムがNot Null だったら、削除とみなされます。
21. OneToMany を設定していて、親のEntityと子供のEntityを一気にpersistしようとしたらエラーが出た
こういう単純な例って、なかなか見つからないんですよね。7
$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のこのクラス を読んでみてください。理由がわかってもらえるはずです。
ちなみに、更新日時を入れたいだけだったら
StofDoctrineExtensionsBundle の Timestampable を使いましょう。
ちなみに22個である理由は、妻が猫好きだからです。
明日は@naoyes さんです!
-
Symfony2はテストが書きやすいと言われています。 ↩
-
自然とJavaっぽいコードになります。Java の Spring Framework に似ていると言われています。 ↩
-
JMSDiExtraBundleを使えば、サービスもアノテーションで定義できます。 ↩
-
そういった意味では、Symfonyは単なる「MVC」フレームワークではない何かです。以前参加したSymfony勉強会でも、ドメイン駆動設計の話題でもちきりでした。 ↩
-
筆者はExcelとCSVを憎んでいます。エンジニアになる前は、Excel職人(運用のひと)でした。 ↩
-
実例をGithubにあげたい。だが時間がない...... ↩
-
Cascade persist する手もありますが、おすすめされていません。 ↩