Убедитесь, что пользователи приложения всегда присутствуют в демо-версии приложения - PullRequest
0 голосов
/ 19 сентября 2011

Я создаю версию существующего приложения Symfony php, которая будет использоваться в качестве песочницы, то есть своего рода демо-версия приложения.Два приложения будут использовать отдельные схемы MySQL на одном сервере.Эти две схемы идентичны, и схема песочницы будет удалена и воссоздана с данными из основного приложения в начале каждого дня.В течение дня пользователи могут создаваться / обновляться в основном приложении, и я хочу, чтобы эти изменения немедленно отражались в приложении-песочнице - поэтому мне нужно копировать изменения примерно из трех связанных таблиц всякий раз, когда они изменяются в основном приложении.

Я рассмотрел возможность создания триггеров для требуемых таблиц в основной схеме, но мне немного не повезло найти примеры триггеров AFTER INSERT и AFTER UPDATE, которые делают что-то вроде.

У меня естьрассматривал возможность изменения объектов Doctrine, связанных с тремя таблицами, для сохранения через отдельную Doctrine_Connection (для песочницы dsn).

Я рассмотрел расширение sfDoctrineGuardPlugin в основном приложении, чтобы обеспечить аутентификацию для обоих приложений, но этовсе еще требуется передача данных из трех таблиц.

Есть ли какой-либо метод, который я здесь не рассматривал?Какой метод будет лучше?

1 Ответ

0 голосов
/ 06 октября 2011

Я решил это, выполнив следующее в кодовой базе песочницы:

  • Реализовал альтернативный валидатор для sfGuardValidatorUser и указал app.yml на этот класс с ключом auth_user_validator.
  • Реализованзакрытый метод проверки _checkMainApp, который вызывается с предоставленными пользователем учетными данными, если пользователь не найден в пользовательской таблице песочницы.Он выполняет следующие действия:
    • устанавливает специальное соединение с основной базой данных приложения (работает с некоторыми ошибками symfony , doctrine )
    • запросить у пользователя основную базу данных (а затем восстановить исходное соединение с базой данных)
    • если пользователь найден и пароль правильный, выполнить глубокое копирование объекта
    • , наконец, толькоПользователь и его профиль должны быть скопированы, и любой другой связанный объект (доступный через пользователя с глубоким копированием) должен быть расположен в базе данных «песочница» и должен заменить существующие отношения - это то, что делает _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://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 я должен убедиться, что любые связанные объекты, которые существуют в основной базе данных, также существуют в базе данных песочницы,но создание новых таких объектов очень ограничено, так что в данном случае это не проблема.

Я не особо в восторге от решения, но оноработает в этом ограниченном контексте, и это достаточно хорошо.

...