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となっています。

doctrine entity __initialized__: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となっていることが確認できます。

initialized-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')

ECCUBE制作トップへ

EC-CUBEカスタマイズに関するお問い合わせはこちら

    脆弱性修正