покритикуйте решение!

Духовность™

Продвинутый новичок
покритикуйте решение!

Вот собственно придумал такую структуру как писать приложения

Моделью являются классы с бизнес-логикой.

PHP:
class User_Model
{
     // ...
}

с базой взаимодействует меппер, который нужен для каждой модели:

PHP:
class User_Mapper
{
     function save(User_Model $object);

     function delete(User_Model $object);

     function findById($id);
}

Контроллеры нужны для каждой страницы, для каждого действия (клика)

PHP:
// редактирование данных пользователя или его добавление 
// в базу
class User_Edit_Controller 
{
    function run()
    {
        // действия идущие в parent-контроллере //
        $this->view = $this->createView(); // создали view (См. ниже что есть view)
        $this->view->loadI18n('common/general', 'user/edit'); // языковые файлы для view 
        $this->view->goHtmlTitle()->add( $this->view->lang->main_title ); // Заполняем title страницы 
        $this->view->goHtmlTitle()->add( $this->view->lang->module_title );
        $this->view->goHtmlTitle()->add( $this->view->lang->controller_title );
        // конец действия идущие в parent-контроллере //
    
        // если был запрошен конкретный пользователь, вытаскиваем о нем информацию
        if ($id = $this->request->getRequest()->id)
        {
            $this->user = $this->user_mapper->findById($this->request->get('id', 'int', 'request'));
        }
    
        // если пользователь не запрошен, это добавление нового
        if (empty($this->user))
        {
            // создаем пустой объектдля view 
            $this->user = $this->user_mapper->createNew();
        }
    
        if (HttpRequest::isPost())
        {
            if (!$validator->getErrors())
            {
                $this->user_mapper->save($this->user);
            }
        }
        
        // отдаем во view объект типа User_Model
        $this->view->user = $this->user;
    }
}

Теперь view.

PHP:
class Base_View
{
    // Хранилище данных
    protected $data;

    // Путь до файла шаблона.
    protected $template;

    // Сгенерированный HTML.
    protected $out;

    // Массив объектов, работающих с view.
    protected $objects = array();

    public function __get($key)
    {
        return $this->data->$key;
    }

    public function __set($key, $value)
    {
        $this->data->$key = $value;
    }

    public function __construct($template)
    {
        $this->template = $template;
        // ....
    }

    /**
    * Функция загружает в представление view в 
    * индекс lang хранилища данных данные в языковом файле,
    * содержащемся по адресу $path, который должен представлять из 
    * себя строку вида имя_модуля/язык/имя_файла_с_языковыми_данными
    */
    public function loadI18n()
    {
        // ...
    }

    /**
    * Возвращает объект Html_Title.
    */
    public function goHtmlTitle()
    {
        if (!isset($this->objects['html_title']) || !$this->objects['html_title'] instanceof Html_Title)
        {
            $this->objects['html_title'] = Html_Title::getInstance(' | ');
        }

        return $this->objects['html_title'];
    }

    /**
    * Возвращает объект View_Helper.
    */
    public function goHelper()
    {
        if (!isset($this->objects['view_helper']) || !$this->objects['view_helper'] instanceof View_Helper)
        {
            $this->objects['view_helper'] = View_Helper::getInstance();
            $this->objects['view_helper']->setFieldErrorTemplate(DOCUMENT_ROOT.'/kernel/templates/field_error_template.phtml');
        }

        return $this->objects['view_helper'];
    }

    // другие функции для вытаскивания других полезных объектов 

    public function run()
    {
        if (!$this->template || !file_exists($this->template))
        {
            throw new Exception('Не найден шаблон <strong>'.$this->template.'</strong> для '.get_class($this));
        }

        ob_start();
        include($this->template);
        $this->out = ob_get_contents();
        ob_end_clean();
    }

    /**
    * Возвращает сгенерированный html-код.
    */
    public function getOut()
    {
        return $this->out;
    }
}

application.php вызывает все это дело примерно так:

PHP:
   public function run()
    {
        try
        {
            $controller = new $controller_name();
            $controller->run();

            if ($view = $controller->getView())
            {
                // ...

                $view->run();
            }

            $this->response->sendHeaders();
            echo $view->getOut();
        } // catch...
    }

Шаблон соответственно выглядит примерно так:

PHP:
<table class="aTable">
    <colgroup>
        <col width="30%" />
        <col width="70%" />
    </colgroup>
    <tr>
        <th colspan="2"><h4>
            <? if($this->user->id): ?>
                <?=$this->lang->editing_user?> <?=Format::hsc( $this->user->getFullName() )?>
            <? else: ?>
                <?=$this->lang->add_user?>
            <? endif; ?></h4>
        </th>
    </tr>
    <tr>
        <td><strong class="compulsory"><?=$this->lang->user_active?>:</strong></td>
        <td>
        <?
        $select = $this->goHelper()->inputSelect('user[user_active]', $this->user->user_active);
        $select->addOption( $this->goHelper()->inputOption(1, $this->lang->yes) );
        $select->addOption( $this->goHelper()->inputOption(0, $this->lang->no) );
        echo $select->getHtml();
        ?>
        </td>
    </tr>
    <tr>
        <td><?=$this->lang->user_group?>:</td>
        <td><?
            $select = $this->goHelper()->inputSelect('user[user_group]', $this->user->user_group);
            $select->addOption( $this->goHelper()->inputOption(0, $this->lang->select_value) );
            foreach ($this->groups as $group):
                $select->addOption( $this->goHelper()->inputOption($group->id, $group->group_name) );
            endforeach;
            echo $select->getHtml();
            ?>
            </td>
    </tr>

ВСЕ меню, "случайные анекдоты" или вывод "последних сообщений форума" я возлагаю на на расширенный Base_View, в котором будет тупо вызываться та или иная модель второстепенных рюшечек:

PHP:
class User_View extends Base_View
{
    public function run()
    {
         $this->menu = new Menu();
         $forum = new forum();
         $this->last_forum_messages = $forum->getLastMessage(10);
         parent::run();
}

Вот.
 
Re: покритикуйте решение!

Автор оригинала: triumvirat
Вот собственно придумал такую структуру как писать приложения
Насчет контроллеров и прочего не скажу. Насчет модели. Мы сейчас пришли к такой схеме



Библиотечные классы здесь сверху и снизу (на схеме не все семантические связи отражены). Доступ к бизнес-модели при таком подходе можно реализовывать множеством способов. В этом конкретном примере используется экспрессивный подход: класс модели является сразу и маппером и entity, навигация вполняется через статические методы, защищенные конструкторы. Это вариант с высокой внутренней связанностью: внутри используются вызовы статических методов ConnectionManager и Domain.

С этими же библиотеками есть реализации через ModelContext + DataMapper + Model где все через впрыск зависимостей без статики вообще. То есть, при таком подходе можно эксперементировать с подходами таская за собой один и тот же функционал в виде либы.
 
if (HttpRequest::isPost())
1) я бы добавил проверку на присутствие имени кнопки отправки формы в массиве $_POST т.к. на странице может быть несколько форм.
2) Если данные не прошли валидацию, то не будет работать автозаполнение уже введенных полей.
3) Используя активные шаблоны можно смешать бизнес логику и логику отображения.
 
Какое отношение метод отправки данных имеет к обработке этих данных?
 
код не весь или не точен
как это может работать?
$this->user_mapper->save($this->user); , если ты только что достал эти данные из быза или создал нового
и зачем хелперы, которые только мешают, это я про option

-~{}~ 04.02.10 21:21:

triumvirat
и когда ты наконец придёшь к компоненты форма?
 
как это может работать?
$this->user_mapper->save($this->user);
а что не так? код не весь естественно, он не рабочий, показана лишь структура

и когда ты наконец придёшь к компоненты форма?
а что это такое?

которые только мешают
ну мне нравитса


Какое отношение метод отправки данных имеет к обработке этих данных?
это кому вопрос?


Если данные не прошли валидацию, то не будет работать автозаполнение уже введенных полей.
будет, объект типа user отдается во view
 
triumvirat
у тебя просто кусок в котором $this->user тащится мепером, а затем сново засовывается в базу. где-то пропущен кусок, где $this->user меняется.

процесс твоего развития похож на пройденный мной путь, я пришёл к формам и спискам как к дополнительным компонентам в mvc. в обязанность форм входит по определённой структуре построить html форму во вью, проверить данные, обработать их и передать их в модель, тем более у тебя мэпер.
 
будет, объект типа user отдается во view
Это понятно :-) Я имел ввиду то, что нигде не стоит условие, откуда приходят данные - из базы или из формы, вот этот кусок кода:
PHP:
        // если был запрошен конкретный пользователь, вытаскиваем о нем информацию 
        if ($id = $this->request->getRequest()->id) 
        { 
            $this->user = $this->user_mapper->findById($this->request->get('id', 'int', 'request')); 
        } 
     
        // если пользователь не запрошен, это добавление нового 
        if (empty($this->user)) 
        { 
            // создаем пустой объектдля view  
            $this->user = $this->user_mapper->createNew(); 
        }
 
Выложу через неделю, через две свой вариант движка.
 
Сверху