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

Духовность™

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

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

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

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();
}
Вот.
 

whirlwind

TDD infected, paranoid
Re: покритикуйте решение!

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



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

С этими же библиотеками есть реализации через ModelContext + DataMapper + Model где все через впрыск зависимостей без статики вообще. То есть, при таком подходе можно эксперементировать с подходами таская за собой один и тот же функционал в виде либы.
 

ps2007

Новичок
if (HttpRequest::isPost())
1) я бы добавил проверку на присутствие имени кнопки отправки формы в массиве $_POST т.к. на странице может быть несколько форм.
2) Если данные не прошли валидацию, то не будет работать автозаполнение уже введенных полей.
3) Используя активные шаблоны можно смешать бизнес логику и логику отображения.
 

whirlwind

TDD infected, paranoid
Какое отношение метод отправки данных имеет к обработке этих данных?
 

AmdY

Пью пиво
Команда форума
код не весь или не точен
как это может работать?
$this->user_mapper->save($this->user); , если ты только что достал эти данные из быза или создал нового
и зачем хелперы, которые только мешают, это я про option

-~{}~ 04.02.10 21:21:

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

Духовность™

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

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

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


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


Если данные не прошли валидацию, то не будет работать автозаполнение уже введенных полей.
будет, объект типа user отдается во view
 

AmdY

Пью пиво
Команда форума
triumvirat
у тебя просто кусок в котором $this->user тащится мепером, а затем сново засовывается в базу. где-то пропущен кусок, где $this->user меняется.

процесс твоего развития похож на пройденный мной путь, я пришёл к формам и спискам как к дополнительным компонентам в mvc. в обязанность форм входит по определённой структуре построить html форму во вью, проверить данные, обработать их и передать их в модель, тем более у тебя мэпер.
 

ps2007

Новичок
будет, объект типа 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(); 
        }
 

HraKK

Мудак
Команда форума
Выложу через неделю, через две свой вариант движка.
 
Сверху