EC-CUBEの3系や4系で開発をしていると必ずDoctrine のEntityのプロパティがどうなっているのか、確認のためdumpを使ったりデバッグツールバーで確認したことがあるはずです。
その際に __isInitialized__: false となっていて、プロパティがid以外全てNULLになっている状態のエンティティを見たことがないでしょうか?
恥ずかしながら私もSymfonyで開発を始めた頃は値が入っていないため、どこかにバグがあるのかと探していました。
しかしDoctrineを学ぶうちにこれは正常な挙動だと気づくことができました。
DoctrineのLazy Loading
Doctrineはデフォルトで、ManyToOneやOneToManyで指定した要素をLazy Loading(遅延読み込み)します。必要になるまで読み込まないという挙動です。
proxyという仕組みが存在し、初めて読み込まれるまでは仮のproxyオブジェクトが割り当てられています。
実際のオブジェクトが割り当てられるのは、ゲッターなどでその要素が必要になったタイミングです。
__isInitialized__: falseという表示がされているのはまだ読み込まれていないよという意味です。
試しに取得したばかりのProductエンティティをdumpしてみるとProductStatusは__isInitialized__: falseとなっています。
getStatusなどでStatusを直接使用するタイミングまでmtb_product_statusテーブルへの問い合わせSQLが発行されません。
Lazy Loadingをさせないようにするには?
それでは遅延ロードさせない方法はあるのでしょうか?いくつか考えられますが、どの場面でも遅延ロードさせないのであれば、Entityのアノテーションにfetch=EAGERを指示します。
/**
* @var \Eccube\Entity\Master\ProductStatus
*
* @ORM\ManyToOne(targetEntity="Eccube\Entity\Master\ProductStatus", fetch="EAGER")
* @ORM\JoinColumns({
* @ORM\JoinColumn(name="product_status_id", referencedColumnName="id")
* })
*/
private $Status;
fetch=EAGERを指示して上と同じ状況のdumpをしてみると、__isInitialized__: trueとなっていることが確認できます。
結局SQL的に何が違う?
fetch=Lazyの場合はゲッターなどでgetStatusが呼ばれるまでSQLを発行しません。
一方、fetch=EAGERでは。ゲッターなどでStatusを直接使用していないのにもかかわらず、
下記のようなmtb_product_statusテーブルへのSQLが発行され、ステータス名などが取得されていることが確認できます。
SELECT t0.id AS id_1, t0.name AS name_2, t0.sort_no AS sort_no_3, t0.discriminator_type FROM mtb_product_status t0 WHERE t0.id IN (1) AND t0.discriminator_type IN ('productstatus')
EC-CUBEに関するお問い合わせ
[重要]現在公式にセキュリティサポートが切れていないPHPは8.1以上、MySQLは8.0以上で、対応しているEC-CUBEバージョンは4.2以上です。古いEC-CUBEを使っている方は適切なタイミングでバージョンアップをご検討ください。