Главная
Блог разработчиков phpBB
 
+ 17 предустановленных модов
+ SEO-оптимизация форума
+ авторизация через соц. сети
+ защита от спама

Применяем делегирование коллективно с наследованием для организации контроллеров действий

Anna | 29.05.2014 | нет комментариев
Добрый день сотрудники, сегодня я расскажу сказку о своём навыке организации контроллеров в плане на ZF 1 (так исторически сложилось).
В отличных книжках по ООП Зачастую пишут, что наследованием невозможно увлекаться, необходимо выбирать делегирование либо делать так, Дабы они трудились коллективно. К сожалению, не неизменно дозволено стремительно додуматься, как применить сухую теорию на практике (а когда наконец-то доходит, изумляешься «что здесь трудного?»), следственно верю мой навык кому-нибудь сгодится.

И так вначале о проблемной области:
31 Controller Action, множество из них имеет способы indexAction(), addAction(), editAction(), searchAction().
задача №1: множество, но не все. В остальных присутствие этих способов варьируется,
задача №2: способы editAction() и addAction() громоздкие сами по себе, и примерно идентичные для всех контроллеров, отличаются инициализация формы, и сохранение модели.

Как я это решил, покажу сразу в коде.

Фрагмент базового класса контроллеров

Class Common_Controller extends Zend_Controller_Action
{
    /**
    * Класс модели связанной с контроллером.
    * @var string;
    */
    protected $modelClass = '';

    /**
    * Класс формы редактирования модели связанной с контроллером.
    * @var string;
    */
    protected $editFormClass  = '';

    /**
    * JS файл, если он необходим, для редактирования модели связанной с контроллером. 
    * @var string;
    */
    protected $jsModelFile = '';

    /**
    * Создает модель связанную с контроллером,
    * если $id передан - ищет в базе, если нет - создает новую. 
    * 
    * @param mixed $id;
    * @return Model_Record $model;
    */
    protected function modelFactory( $id = null )
    {
        $modelClass = $this->modelClass;
        if  ( $id )  {
            $model = $modelClass::find( $id );    
        }
        else {
            $model = $modelClass::create();
        }
        return $model;
    }

    /**
    * Создает форму редактирования связанную с контроллером.
    * 
    * @param Model_Record $model;
    * @return Zend_form $form;
    */
    protected function formFactory( Model_Record $model )
    {
        $formClass = $this->editFormClass;
        $form = new $formClass();
        $form->setDefaults( $model->toArray(1) );
        return $form;
    }

    /**
    * Заполняем модель данными из формы и сберегаем. 
    * 
    * @param Model_record $model;
    * @param Zend_Form $form;
    */
    protected function save( Model_Record $model , Zend_Form $form )
    {
        $model->fromArray($form->getValues(), false);
        $model->save();
    }

    /**
    * Хелпер редактирования сущности, 
    * этому способу делегируются вызовы editAction() в производных контроллерах.
    */
    protected function _editActionHelper()
    {
        $id = $this->_request->getParam('id');
        if ( !$id ) {
            throw new Zend_Controller_Action_Exception('страница не обнаружена' , 404); 
        }
        // модель поднимаем 
        $model = $this->modelFactory($id); 

        if ( !$model ) {
            throw new Zend_Controller_Action_Exception('страница не обнаружена' , 404); 
        }

        $this->view->model = $model;

        // заголовок страницы
        $this->view->PageTitle = $model->getFullTitle();

        // форму редактирования создаем
        $form  = $this->formFactory( $model );
        $this->view->form = $form;

        // если страница загружена get-ом - прокидываем дальше (через форму) реферер, куда возвратиться позже сохранения 
        if ( $this->_request->isGet() )  {
            $form->redirect->setValue( $_SERVER['HTTP_REFERER']  );
        }

        // проверяем, есть ли права на редактирование записи
        // ...

        // блокируем запись
        $model->lock();

        // js файл подключаем
        if ( $this->jsModelFile ) {
            $this->view->headScript()->appendFile( '/js/models/' . $this->jsModelFile );
        }

        // сберегаем данные
        if ( isset($_POST['save']) || isset($_POST['saveExit']) ) {
            // валидация
            if (  $form->isValid( $this->_request->getPost() )  )  {    
                // пробуем сберечь 
                try {
                    Model::connection()->beginTransaction();

                    $this->save( $model, $form );

                    Model::connection()->commit(); 

                    $model->releaseLock();

                    $this->view->Flash()->addSuccess( 'Success !' ); 

                    // решаем, что делать позже сохранения 
                    // возвратиться на эту же страницу
                    $redirect = '/' . $this->_request->getControllerName() . '/edit/id/' . $model->ID
                              . '?redirect=' . $this->_request->getParam('redirect', '/');

                    // сберечь и выйти 
                    if ( isset($_POST['saveExit']) ) {  
                        $redirect = $this->_request->getParam('redirect', '/'); 
                    }

                    $this->_redirect( $redirect );
                }
                catch (Exception $e) {     
                    Model::connection()->rollback();
                    $this->view->Flash()->addError( $e->getMessage() );
                }
            }
            else {
                $this->view->Flash()->addError("Форма заполнена с ошибками");
            }
        }
    }
}

Protected способ modelFactory() создает экземпляр модели, связанной с определенным контроллером. Класс модели указывается в переменной $this->modelClass и в большинстве случаев, кастомизация на этом заканчивается. Если модель должна быть инициализирована по особенному, то легко переопределяем данный способ в определенном контроллере.

Protected способ formFactory() создает форму редактирования, кастомизация подобно modelFactory().

Protected способ save() сберегает в переданную модель данные из переданной формы, тут также есть место для маневра, если в определенном контроллере сохранение сущности получается развесистым. Присутствие такого способа в контроллере может вызвать сомнение, следственно поясню, в save() допускаются только вызовы дополнительных способов модели, никаких sql запросов нет, для этого в модели мы определяем способы как бы addTag(), setChannles() и т.п. взамен одного непрозрачного способа saveFromArray().
При такой композиции, модель и форма ничего не знают друг о друге, а контроллер играет роль интегратора.

Конечный protected способ в этом фрагменте это _editActionHelper(), если в производном классе нам потребуется помощь редактирования сущности, то мы легко добавляем в него способ:

    public function editAction()
    {
         $this->_editActionHelper();
    }

Подобно для других всеобщих способов. Фрагмент производного контроллера для примера:

Class Video extends Common_Controller
{
    protected $modelClass = 'Video';
    protected $editFormClass  = 'Form_Video';

    protected function save( Model_Record $model , Zend_Form $form )
    {
           parent::save(  $model ,   $form );
           $model->setChannels( $form->channels->getValue() );
    }

    public function editAction()
    {
           $this->_editActionHelper();
    }

    public function addAction()
    { 
           $this->_addActionHelper();
    }

    public function indexAction()
    {
           $this->_indexActionHelper();
    }
}

P.S. просьба, если что-то ни так, пишите в комментарии, это будет пригодно каждому читателям.

Источник: programmingmaster.ru

Оставить комментарий
Форум phpBB, русская поддержка форума phpBB
Рейтинг@Mail.ru 2008 - 2017 © BB3x.ru - русская поддержка форума phpBB