Класс UserLog и MVC

Baranov_Dron

Новичок
Класс UserLog и MVC

В общем есть задача для админа вести удобочитаемый и просматриваемый лог действий юзеров - регистрация, смена email, вход, неудачный вход, подтверждение по email и так далее.
И я споткнулся с этой задачей на следующих шагах и прошу совета.

Первое, как лучше всё же вести лог
PHP:
//так
class userActions extends sfActions
{
    public function executeRegister($request)
    {
        $this->form = new RegisterForm;
        if ($request->isMethod('post'))
        {
            $this->form->bind($request->getParameter('register'));
            if ($this->form->isValid())
            {
                $values = $this->form->getValues();
                $log = new UserLog;
                $log->setAction('register');
                $log->setResult('Регистрация прошла успешно, ссылка активации выслана. Регистрация по реф id');
                $log->save();
                $user = new User;;
                $user->setLogin($values['login']);
                $user->save();
                $user->link('UserLog', array($log->getId()));
            }
        }
    }
}

//или так

class userActions extends sfActions
{
    public function executeRegister($request)
    {
        $this->form = new RegisterForm;
        if ($request->isMethod('post'))
        {
            $this->form->bind($request->getParameter('register'));
            if ($this->form->isValid())
            {
                $values = $this->form->getValues();;
                $user = new User;;
                $user->setLogin($values['login']);
                $user->save();
                
                Doctrine::getTable('UserLog')->addLog('register', 
                  'Регистрация прошла успешно, ссылка активации выслана. Регистрация по реф id', $user->getId());
            }
        }
    }
}
?

Второе, есть action в контролере - подтверждение email
PHP:
class userActions extends sfActions
{
    public function executeConfirm($request)
    {
        if ($request->isMethod('post'))
            return $this->forward404();
        if (!$this->getUser()->confirmRegistration($request->getParameter('id'), $request->getParameter('key')))
            return $this->forward404();
    }
}
И класс myUser(выше он вызывался, как $this->getUser())
PHP:
class myUser extends sfBasicSecurityUser
{
    public function confirmRegistration($id, $key)
    {
        $table = Doctrine::getTable('UserConfirm');
        if ($record = $table->retrieveByUserID($id))
        {
            if ($record->getRemember_key() == $key)
            {
                $record->User->setIsconfirm(1);
                $record->save();
                Doctrine::getTable('UserLog')->addLog('confirm', 'Email адрес '.$record->User->getEmail().' подтверждён.', $record->User->getId());
                $record = '';
                $table->delitByUserID($id);
                return TRUE;
            }
            else
                return FALSE;
        }
        else
            return FALSE;
    }
}
Вопрос в том, кто должен писать лог, класс myUser или userActions(он же контролер)?
 

korchasa

LIMB infected
1. Лог должен быть отдельным объектом, т.к. может получиться, что в определённый момент таблица в базе перестанет вас удовлетворять.
2. Делать логирование в модели ИМХО некрасиво, т.к. появляется не нужная зависимость + непонятно, как пропускать действия от модераторов (например, поправили имя через админку). Мы делаем в экшенах, либо в сервисах, если они есть.


ЗЫ: Я бы и confirmRegistration из модельки убрал.
 

Baranov_Dron

Новичок
<Делать логирование в модели ИМХО
Вот и я об этом же подумал. Отвратительно выглядит в модели лог.
<может получиться, что в определённый момент таблица в базе перестанет вас удовлетворять
Об этом я не подумал...
<ЗЫ: Я бы и confirmRegistration из модельки убрал.
А чем тебе не нравится эта функция?
User - модель, класс phpDoctrine
А myUser - вспомогательный класс, где располагаются методы класса типа регистрация, подтверждение и т.д.
Я откровенно говоря эту идея скопировал с плагина sfDoctrineGuardPlugin
<Мы делаем в экшенах, либо в сервисах, если они есть.
В экшенах я не хочу по простой причине - они становятся большими, а вообще во многих книгах рекомендация, чтоб экшн был небольшим.
А сервисы - это и есть в симфони events, ссылку на которую дал Black Raven?
 

korchasa

LIMB infected
Автор оригинала: Baranov_Dron
<ЗЫ: Я бы и confirmRegistration из модельки убрал.
А чем тебе не нравится эта функция?
User - модель, класс phpDoctrine
А myUser - вспомогательный класс, где располагаются методы класса типа регистрация, подтверждение и т.д.
Я откровенно говоря эту идея скопировал с плагина sfDoctrineGuardPlugin
Обычно схема регистрации, подтверждения, напоминания пароля, и т.д. одна и та же. Поэтому хорошо подходит для повторного использования в других проектах.

Автор оригинала: Baranov_Dron
<Мы делаем в экшенах, либо в сервисах, если они есть.
В экшенах я не хочу по простой причине - они становятся большими, а вообще во многих книгах рекомендация, чтоб экшн был небольшим.
Ну от одной строчки он сильно не разрастётся (мы оптимисты :) ):
PHP:
UserActionsLog::instance()->add(UserActionsLog::ACTION_REGISTRATION, $user_id);
Ну а если не нравится ни модель, ни экшн, то придется добавлять что-то между ними ;)
Автор оригинала: Baranov_Dron
А сервисы - это и есть в симфони events, ссылку на которую дал Black Raven?
классика - http://martinfowler.com/eaaCatalog/serviceLayer.html
для нас - что-то между контроллером и моделями, введенное чтобы отвязать модели друг от друга, и не "засорять" модели несвойственными ее положению действиями(отсылка почты, работа с запросом и ответом, логирование).
 

Baranov_Dron

Новичок
А поподробнее можешь рассказать про "что-то между контроллером и моделями"?
 

korchasa

LIMB infected
Автор оригинала: Baranov_Dron
А поподробнее можешь рассказать про "что-то между контроллером и моделями"?
Сугубое ИМХО, которое быстро разнесут в пух и прах адепты ООП ;)
1. Куски контроллеров, которые хочется протестировать или перетащить в другой проект - MemberRegistrationService.
2. Организация единой точки для двух разных интерфейсов (HTTP, FTP и т.д.) - MemberAuthorizationService
3. Сервис отделяющий логику приложения от логики доменной области (работа с куками, запросом, ответом, логами и т.д.) - CommentsPresentationHelper
4. Работа с данными, которые не хочется делать в модели - PhotoUploadManager

В общем мы сами пока делаем на ощущениях, и не выработали чётких соглашений. Даже по именам это видно (manager, helper, service).
 

Baranov_Dron

Новичок
По поводу темы топика, сделал так
PHP:
//контроллёр
class userActions extends sfActions
{
    public function executeConfirm($request)
    {
        if ($request->isMethod('post'))
            return $this->forward404();
        if ($this->getUser()->confirmRegistration($request->getParameter('id'), $request->getParameter('key')))
            $this->dispatcher->notify(new sfEvent($this, 'user_logger.confirm_success', array('id' => $request->getParameter('id'))));
        else
            return $this->forward404();
    }
}
//слушаем собитие "user_logger.confirm_success" и передаём управление UserLogger::confirmSuccess
class frontendConfiguration extends sfApplicationConfiguration
{
    public function configure()
    {
  	    $this->dispatcher->connect('user_logger.confirm_success', array('UserLogger', 'confirmSuccess'));
    }
}

class UserLogger
{
    public static function signinSuccess(sfEvent $event)
    {
        $log = new UserLog;
        $log->setUserId($event['id']);
        $log->setAction('signin_success');
        $log->setResult('Пользователь с id '.$event['id'].' авторитизован.');
        $log->save();
    }
}
?>
Сделано на основе мана, по ссылке, которую дал Black Raven и плагина sfDoctrineErrorLoggerPlugin.
Мне нравится такое решение, korchasa и Black Raven спасибо за советы.

А по поводу последнего поста, korchasa, а вы сами-то не запутались с таким обилием классов?
И это на основе фреймворка limb?(кстати http://limb-project.com/ что-то не открывается :()
 

korchasa

LIMB infected
Автор оригинала: Baranov_Dron
...
А по поводу последнего поста, korchasa, а вы сами-то не запутались с таким обилием классов?
И это на основе фреймворка limb?(кстати http://limb-project.com/ что-то не открывается :()
Если их нормально располагать и называть, то проблем нет. В лимбе > 200K строк и ничего :)
Насчет сайта в курсе - сервер барахлит.
 
Сверху