我正在创建一个现有symfony php应用程序的版本,该应用程序将用作沙盒,即应用程序的一种演示版本。 这两个应用程序将在同一台服务器上使用单独的mysql架构。 这两个模式是相同的,沙盒模式将被删除,并在每天开始时使用主应用程序中的数据重新创建。 在白天,可以在主应用程序中创建/更新用户,我希望这些更改立即反映在沙盒应用程序中 - 因此,我需要在主应用程序中更改时从大约三个相关表中复制更改。 / p>
我考虑过在主模式中的必需表上创建触发器,但是我很幸运找到了AFTER INSERT和AFTER UPDATE trigger_body的例子。
我考虑过修改与这三个表关联的Doctrine对象,以便通过单独的Doctrine_Connection(对于沙箱dsn)进行保存。
我考虑在主应用程序中扩展sfDoctrineGuardPlugin以为这两个应用程序提供身份验证,但这仍然需要从三个表中传输数据。
我有没有考虑过这方法?哪种方法最好?
答案 0 :(得分:0)
我通过在沙箱代码库中执行以下操作解决了这个问题:
# 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://root@localhost/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失败,我必须确保主数据库中存在的任何相关对象也存在于沙箱数据库中,但是创建新的此类对象非常有限所以它是在这种情况下并不是真正的问题。
我并不是特别迷恋这个解决方案,但它在这个有限的环境中工作,这已经足够了。