Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Entity をセッションに格納し、再取得した際に __PHP_Incomplete_Class となってしまう場合がある #1680

Closed
nanasess opened this issue Aug 17, 2016 · 5 comments
Labels
document Improvements or additions to documentation wontfix
Milestone

Comments

@nanasess
Copy link
Contributor

Entity をセッションに格納し、再取得した際に __PHP_Incomplete_Class となってしまう場合がある。

Lazy loading 対象となった Entity は Doctrine Proxy クラスを経由して取得するが、このインスタンスをセッションに格納し、再取得しようとすると、 __PHP_Incomplete_Class となってしまう。

通常、 session_start() の際に、対象となるクラスのファイルを読み込んでおく必要がある。
しかし、 Doctrine Proxy のキャッシュファイルを読み込むのは、 session_start() より後のタイミングになるため、 __PHP_Incomplete_Class となってしまう。

以下の検証コードで再現する。

class TopController
{

    public function index(Application $app)
    {
        $Customer = $app['eccube.repository.customer']->find(1);
        $session = $app['session'];

        if (!$session->has('pref')) {
            // XXX ここでは \Eccube\Entity\Master\Pref ではなく Doctrine Proxy オブジェクトが返ってくる
            $Pref = $Customer->getPref();
            $session->set('pref', $Pref);
        }
        $Pref = $session->get('pref');
        // __PHP_Incomplete_Class となってしまう
        dump($Pref);
        return $app->render('index.twig');
    }
}

解決には unserialize_callback_func を実装する必要がある
http://php.net/manual/ja/var.configuration.php#unserialize-callback-func

参考
doctrine/orm#2345 (comment)

@nanasess
Copy link
Contributor Author

nanasess commented Aug 17, 2016

以下のような修正で対応可能。

modified   src/Eccube/Application.php
@@ -292,6 +292,7 @@ class Application extends ApplicationTrait

     public function initSession()
     {
+        ini_set('unserialize_callback_func', 'Eccube\Application::proxymissing');
         $this->register(new \Silex\Provider\SessionServiceProvider(), array(
             'session.storage.save_path' => $this['config']['root_dir'].'/app/cache/eccube/session',
             'session.storage.options' => array(
@@ -997,4 +998,13 @@ class Application extends ApplicationTrait
         }
         return true;
     }
+
+    public static function proxymissing( $name ) {
+        $proxyDir = __DIR__.'/../../app/cache/doctrine';
+        if ( strpos($name, 'DoctrineProxy\__CG__\Eccube\Entity') !== false) {
+            $name = str_replace('\\', '', $name);
+            $name = str_replace('DoctrineProxy', '', $name);
+            require $proxyDir.'/'.$name.'.php';
+        }
+    }
 }

しかし、 Doctrine Proxy クラスファイルが存在しない場合はエラーになってしまうため、 console コマンドで生成しておく必要がある

php ./vendor/bin/doctrine orm:generate-proxies

参考
http://docs.doctrine-project.org/projects/doctrine-orm/en/latest/reference/advanced-configuration.html#auto-generating-proxy-classes-optional

@ryo-endo ryo-endo added this to the 3.0.x milestone Aug 19, 2016
@ryo-endo ryo-endo added the bug label Aug 19, 2016
@ryo-endo ryo-endo changed the title unserialize problem Entity をセッションに格納し、再取得した際に __PHP_Incomplete_Class となってしまう場合がある Sep 28, 2016
@Yangsin Yangsin added bug:Middle and removed bug labels Oct 13, 2016
@nanasess
Copy link
Contributor Author

nanasess commented Dec 5, 2016

本 issues の修正案を適用すると、ブロック管理で Doctrine のキャッシュが削除され、システムエラーが発生してしまう模様

#1953

@ttsuru
Copy link
Contributor

ttsuru commented Dec 5, 2016

SymfonyではEntityをSessionに入れない設計がベストプラクティス的な感じがあります。

@Yangsin Yangsin added document Improvements or additions to documentation wontfix and removed bug:Middle labels Jan 6, 2017
@Yangsin Yangsin modified the milestones: Not release, 3.0.x Jan 6, 2017
@Yangsin
Copy link

Yangsin commented Jan 6, 2017

「SessionにEntityを入れない」という内容を開発のガイドラインなどに追加することにします。

@chihiro-adachi
Copy link
Contributor

本体側では解消されているため、クローズします。

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
document Improvements or additions to documentation wontfix
Projects
None yet
Development

No branches or pull requests

5 participants