2011-09-19 21 views
0

我正在創建一個現有的將用作沙盒的symfony php應用程序的版本,即某種演示版本的應用程序。 這兩個應用程序將在同一臺服務器上使用單獨的mysql模式。 這兩個模式是相同的,沙盒模式將在每天開始時從主應用程序的數據中刪除和重新創建。 白天,用戶可能會在主應用程序中創建/更新,我希望這些更改立即反映在沙盒應用程序中 - 所以我需要在主應用程序中更改時從三個相關表中複製更改。確保應用程序的用戶始終處於應用程序的演示版本中

我已經考慮在主模式中的所需表上創建觸發器,但我有點運氣找到AFTER INSERT和AFTER UPDATE的trigger_body的例子。

我曾考慮修改與三個表關聯的Doctrine對象以通過單獨的Doctrine_Connection(對於sandbox dsn)進行保存。

我曾考慮過在主應用程序中擴展sfDoctrineGuardPlugin以爲這兩個應用程序提供身份驗證,但這仍然需要從三個表中傳輸數據。

有沒有我沒有考慮過的方法?哪種方法最好?

+0

同步這兩個數據庫是否適合您?如果它們都在同一臺服務器上,應該很容易完成。而且它還會考慮到每天早上同步的需要。 – jdias

+0

你是指複製嗎?不斷更新沙箱數據庫與主數據庫的變化?我肯定會嘗試這樣做(雖然可能有一些表我不想用這種方式進行同步),但據我瞭解,複製在同一臺服務器中是不可能的。我錯了嗎? – jah

+1

是的。我的意思是複製。最常見的實現是在2個不同的服務器之間進行復制。但是,您可以在同一臺服務器上安裝兩個MySQL實例,並且可以像在不同服務器中一樣進行復制。 – jdias

回答

0

我解決了這個做在沙箱中的代碼庫執行以下操作:

  • 實現了另驗證程序sfGuardValidatorUser,尖app.yml這一類的auth_user_validator關鍵。
  • 實施私人驗證程序方法_checkMainApp,如果在沙箱用戶表中找不到用戶,則使用用戶提供的憑據調用該方法。它具有以下功能:
    • 設置到主應用程序數據庫(周圍的一些錯誤工作symfonydoctrine
    • 查詢主數據庫用戶(然後恢復原來的數據庫連接)的ad-hoc連接
    • 如果找到用戶並且密碼良好,請最後執行對象的深層副本
    • 應該只複製用戶及其個人資料,並且應該找到任何其他相關對象(可通過深複製用戶使用)在沙箱數據庫中,並應該替換現有的關係 - 這是_fixCopiedRelations的做法(以相當麻煩的方式)。


# lib/validator/yiValidatorUserSandbox.class.php 
    protected function doClean($values) 
    { 
     // snip 

     // don't allow to sign in with an empty username 
     if ($username) 
     { 
      // snip 

      // user exists? 
      if ($user) { 
       // password is ok? 
       // snip 
      } else if ($user = $this->_checkMainApp($username, $password)) { 
       return array_merge($values, array('user' => $user)); 
      } 
     } 
     // snip 
    } 

    private function _checkMainApp($username, $password) 
    { 
     $sandConn  = Doctrine_Core::getTable('sfGuardUser')->getConnection(); 
     $readOnlyConn = Doctrine_Manager::connection(
      'mysql://[email protected]/maindb', 'readonly' # readonly is only the conn name, not its state 
     ); 
     $user = Doctrine_Core::getTable('sfGuardUser') 
      ->getAllUserDetailsUsingConnection($username, $readOnlyConn); 
     Doctrine_Manager::getInstance()->closeConnection($readOnlyConn); 
     Doctrine_Manager::getInstance()->setCurrentConnection($sandConn->getName()); 
     if ( $user instanceof sfGuardUser && $user->getIsActive() 
      && $user->checkPassword($password) 
     ) { 
      $sandboxUser = $user->copy(true); 
      $this->_fixCopiedRelations($sandboxUser); 
      $sandboxUser->setPasswordHash($user['password']); 
      $sandboxUser->save($sandConn); 
      return $sandboxUser; 
     } 
     return false; 
    } 

    private function _fixCopiedRelations(Doctrine_Record $rec) 
    { 
     $rel = $rec->getReferences(); 
     foreach ($rel as $name => $related) { 
      if ($name == 'Responsibilities') { 
       $coll = new Doctrine_Collection('Client'); 
       foreach ($related as $client) { 
        $o = Doctrine_Core::getTable('Client')->findOneByCode($client['code']); 
        if ($o instanceof Client == false) { 
         throw new UnexpectedValueException(
          'Cannot find related object in the sandbox database, therefore not copying sfGuardUser to the sandbox.' 
         ); 
        } 
        $coll->add($o); 
       } 
       $rec[$name] = $coll; 
      } else if ($name == 'Groups' || $name == 'Permissions') { 
       $coll = new Doctrine_Collection(($name == 'Groups' ? 'sfGuardGroup' : 'sfGuardPermission')); 
       foreach ($related as $instance) { 
        $o = Doctrine_Core::getTable(($name == 'Groups' ? 'sfGuardGroup' : 'sfGuardPermission'))->findOneByName($instance['name']); 
        if ($o instanceof Doctrine_Record == false) { 
         throw new UnexpectedValueException(
          'Cannot find related object in the sandbox database, therefore not copying sfGuardUser to the sandbox.' 
         ); 
        } 
        $coll->add($o); 
       } 
       $rec[$name] = $coll; 
      } else if ($name == 'Profile') { 
       $this->_fixCopiedRelations($related); 
      } else { 
       throw new UnexpectedValueException(
        'Method does not know how to copy this related object to the sandbox, therefore not copying sfGuardUser to the sandbox' 
       ); 
      } 
     } 
    } 

值得一提的是,爲了防止_fixCopiedRelations的失敗,我必須確保存在於主數據庫的任何相關對象也存在於沙盒分貝,但創作新的這樣的物體是非常有限的,所以在這種情況下它不是真正的問題。

我並不特別喜歡這個解決方案,但它在這個有限的背景下工作,這已經足夠好了。