Шаги к MVC или как правильно (или неправильно) сделать проект

Alexandre

PHPПенсионер
Чтобы идти к MVC, надо чётко разделять Контроллер (обработчик, диспетчер запроса), Модель (вся прочая логика), Вид (отображение информации). В том, что ты привёл, я не вижу никакого разделения на эти три составные вообще - только разбивку на модули.
Ямерт согласен,
структура четко разделена на три составные части:
1) Контроллер (обработчик, диспетчер запроса) реализуется в классе $page->init()
2) логика в классах наследниках от $page
3) Вид (отображение информации) в виде XSLT шаблонов

для идеологии уж лучше доки к struts почитать
chameleon прежде чем состряпать что-то свое - и стратс читал и пытался с турбиной разобраться. Думаешь описывать действия контроллера xml файлами - лучший вариант?

С точки зрения продуктивности работы -- модуль это файл на 30-300 строк кода,
тогда кол-во файлов возрастает до 300 и более и начинаешь путаться в каком файле что реализованно - разве это не лучший вариант для продуктивности?:D :D
 

Screjet

Новичок
>тогда кол-во файлов возрастает до 300 и более и начинаешь путаться в каком файле что реализованно - это не лучший вариант для продуктивности

Он в чем-то прав: супертяжелые файлы еще хуже. Можно (как в жаве) группировать файлы по каталогам (тоже с продуманной структурой).
 

chameleon

Новичок
Думаешь описывать действия контроллера xml файлами - лучший вариант?
имхо, уж самый удобный для описания точно. Быстродействия конечно не добавляет, а какие есть еще альтернативы?

Вообще, мне более нравятся cocoon-подобные (Krysalis) с евойными пайплайнами, но вызывает сомнения использование в промышленных масштабах... а так там все вкусности уже builtin - тут тебе и taglibs и xslt в шаблонах, и soap....эх найти бы время поиграться..а мож кто уже?
 

Alexandre

PHPПенсионер
Можно (как в жаве) группировать файлы по каталогам (тоже с продуманной структурой)
Screjet Нужно искать золотую середину, и я стараюсь ее придерживаться. Если я чуствую, что мой класс превращается в "супертяжелый файл", я используя все предести ООП и разбиваю его на подклассы. В Яве есть пакеты, которые в принципе можно ассоциировать с каталогами. С таким же успехом, модуль может состоять из основного файла и файлов с вспомогательными классами, которые можно запихнуть в один из каталогов (данной папки или /base - основные классы и модули).

-~{}~ 01.09.04 12:06:

прочитал умную книгу:
у меня отделение контроллера от логики заключается в
след коде:
PHP:
			switch(action)
			{

				case "all" :
					str = all();					
					break;

				case "cancel" :
					cancel(id);
					str = all();										
					break;

				case "delete":
					this.delete( id );
					str = all();					
					break;
}
Думаю это можно как-то вынести?
 

Orlis

Guest
this.delete( id );
Топик и так абстрактен до бесполезности, а теперь еще код-фантазия...

Причем тут PHP?
 

_RVK_

Новичок
у меня отделение контроллера от логики заключается в
след коде
Это то что я пытался объснить с самого начала.
Думаю это можно как-то вынести?
Не мона у нуно :)

А вообще, можешь привести диаграмму класов? A то все приходится представлять в голове, что не есть удобно
 

Alexandre

PHPПенсионер
А вообще, можешь привести диаграмму класов? A то все приходится представлять в голове, что не есть удобно
принято, буду рисовать (возможно с ошибками :)))

Топик и так абстрактен до бесполезности, а теперь еще код-фантазия...
код C#
но у меня такой же принцип реализации на пхп
тут что важно - идея
куда двигаться и как правильно создавать MVC WEB-приложения

а как правильно отделить Контролер от Модели?
язык и реализация - дело уже второе, а то и третье
 

Screjet

Новичок
Нужно четко разделить "главный-подчиненный". Кто на что влияет и приоритеты.
Например как у меня:
PHP:
$tmpl = new template1( new controller1() );
 

Alexandre

PHPПенсионер
MVC - Модель Представление Контроллер

Нужно четко разделить "главный-подчиненный". Кто на что влияет и приоритеты.
Например как у меня:

$tmpl = new template1( new controller1() );
Screjet
т.е. у тебя каждый контроллер передает
в "Класс Представления" имя шаблона?
а где МОДЕЛЬ?
MVC - три буквы - три части:
Модель
Контроллер
Представление.

а у тебя два уровня: Контроллер - Представление
 

Screjet

Новичок
А можно дать определение модели?
(сорри, но в терминах плаваю)
 

wrapper

Guest
Alexandre
Думаешь описывать действия контроллера xml файлами - лучший вариант?
когда то пришло вдохновение написать фреймворк. Конфиг, описывающий структупу всего приложения (модули, действия, роли и пр.) в xml. А при каждом изменении он компилится в php файл и потом просто инклудится. чем не вариант?
 

Alexandre

PHPПенсионер
А при каждом изменении он компилится в php файл и потом просто инклудится. чем не вариант?
wrapper кстати вариант интерестный,
но есть рабочие модули?

Модель: в объектно-ориентированном контексте - наиболее "чистой" формой Модели является объект предметной области.
В нашем случае - под Моделью является набор "классов описания предметной области":
Пользователь
Товар
Новость
Монета

Класс предметной области - это ни есть страница вывода или обработки.

Страница вывода или обработки (как правило за это отвечает одна WEB страница) может использовать разные элементы (классы) предметной области.
 

Screjet

Новичок
Ага, ясно. Ну контролер как раз и занимается тем, что создает нужные модели в зависимости от событий.

Но что однозначно: данные от модели не идут прямо на вывод (в шаблон) а проходят через конролер. Скажем, шаблон "знает" API контролера, но ничего не знает про модели. А контролер знает API моделей.
 

Alexandre

PHPПенсионер
Уровень идей!

хотел чему-то научить Новичков, но оказалось:
векь живи - век учись ;):D

Логика работы классической MVC следующая :
Все поступающие запросы от Пользователя обрабатывает Котроллер. Контроллер осуществляет димпечеризацию действий, значения переменной $_REQUEST["action"] и вызывает соответствующий метод Модели бизнес-объекта,
значение которого соответствует переменной $_REQUEST["model"] .

Данные для Бизнес-объекта могут соответствовать одному или нескольким "Источникам данных" (т.е. их представление может соответствовать одной или нескольким таблицам БД).

В Конфигурационном файле MVConfig.xml содержится логика соответствия слоев между уровнями C-M и V-М.

После анализа значения $_REQUEST["action"] и $_REQUEST["model"] по данным из MVConfig.xml инклудится соответствующий бизнес объект, иницииализируется класс бизнес-объекта [model] и реализуется его метод [action].

После реализации метода [action] анализируется код возврата
Код:
 и в соответствии с возвращенным кодом реализуется соответствующий метод [action] "Источника данных" (инклудится соотвкетствующий класс Источника данных и выполняется соотвкетствующий метод класса.)

Результатом реализации метода [action] Класса "Источника данных" является строка внешнего представления данных.

Метод [action] использует из данных MVConfig.xml соответствующий шаблон.

Данная строка может быть как конечным результатом, так и представлять собой Шаблон представления данных (уровень View).

Предлагаю след. структуру MVConfig.xml:
[php]<MVConfig>
	<action name=[value of $_REQUEST[action]]>name of method 
		<model name=[value of $_REQUEST[model]]>name of business objects</>
		<DataSource code=[return code class of model] name=[name of DataSource objects] template=[name of template] >name of DataSource object method</>
	</action >

	<action name="all" >all 
		//т.к. нет данных для бизнес-модели, то тег <model> опущен
		<DataSource name="userDS" template="user_view" >viewAll</DataSource> 
		// идет вызов метода viewAll объекта name="userDS
		// по окончанию отработки - вызывается шаблон template="user_view	
	</action >

	<action name="edit" >edit 
		<model name="users" ]>update</model> 	// осуществляется вызов метода update
							//класса name="users" 
		<DataSource name="userDS" template="user_view" >viewAll</DataSource> 
		// При коде возврата =0 реализации метода объекта users
		// идет вызов метода viewAll объекта name="userDS
		// по окончанию отработки - вызывается шаблон template="user_view	

		<DataSource code=1 name="userDS" template="user_edit" >edit</DataSource> 
		// При коде возврата =1 /* ошибка в принятых на редактирование данных  */
		// реализации метода объекта users
		// идет вызов метода edit объекта name="userDS
		// по окончанию отработки - вызывается шаблон template="user_edit	
		// 
		// на один код возврата Контроллера может быть сформированно несколько откликов 
		// от разных источников данных.

	</action >

</MVConfig>[/php]

[size=1][i]-~{}~ 02.09.04  10:08:[/i][/size]

[b]Screjet[/b]
не знаю ответил-ли я на твой вопрос.
__________________________________________________
на первом этапе вместо парсинга конфига, можно использовать MVConfig.php, который представляет массив адекватной MVConfig.xml структуры. 
Эту идею (идею конфига) я украл из phpmvc, а ее представление в xml из strats

[size=1][i]-~{}~ 02.09.04  10:13:[/i][/size]

____________________________________________________
остается еще продумать решение нескольких вопосов на счет отработки нескольких ДатаСоурсов и вывод на несколько разных шаблонов.

Достоинство предложенной идеи:
- минимальный рефакторинг
- отсутствие повторного использования кода (чем страдают большинство WEB приложений)
- возможность одновременного использования нескольких шаблонов
 

wrapper

Guest
Re: Уровень идей!

Автор оригинала: Alexandre
>кстати вариант интерестный,
>но есть рабочие модули?

Есть конечно. Только понятие модуль для каждого имеет свой смысл.
Вот как все это у меня:

1) Engine
Контроллер через который идут все запросы.
Определяет обработчик для запроса, загружает его (require_once($path_to_class)) и дает все необходимое для работы как то: $db, $log, $template_engine, $context(user, locale)
Использует конфиг для определения обработчика и генерации результирующей страницы.

2) Module
Класс содержащий в себе только методы бизнес логики.
Использует предоствляемые Engin-м $db, $log и пр.

Пример:

PHP:
class UserModule extends AbstractModule() {
    insert($user) {}
    update($user) {}
    listAllUsers() {}
    ....
}
3) View
Для каждого модуля может быть сколько угодно View классов.
Использует $template_engine, $context предоставляемы Engin-м
Пример:

PHP:
class UserLoginView extends AbstractView {
    render() {
	//здесь может использоваться функциональность модуля и переменные ложатся в темплейт
        return $this->engine->$smarty->fetch("fo/user/loginForm.tpl.html"); 
        //или просто 
       //return "<form>...</form>";
    }    
}
результирующая страница это набор таких вьюшек + статических компонентов (хидер, футер, меню, пр.)

4) Container
Обязательно имеет темплейт. Содержит в себе произвольное кол-во View и других контейнеров.
Для каждого запроса Engine определяет root контейнер. А потом все рекурсивно парсит свои темплейты.
Класса для контейнера нету, он существует только в конфиге.

5) Конфиг
имеет такой вид:
PHP:
<project>	
	<!-- 
		Users defined here can be used for testing, quick start or in simple applications
		In majority of cases you will use users stored in database 		
	-->		   
	<roles>
		<role id="anonymous"/>							
		<role id="user"/>			
		<role id="admin"/>				
	</roles>
		
	<users>
	    <user id="user" password="user" role="user"/>
	    <user id="admin" password="admin" role="admin"/>		
	</users>	
	
	<modules>		
		<module id="ErrorModule" className="ErrorModule" classPath="error/ErrorModule.php">
			<view id="FOErrorView" className="FOErrorView" classPath="error/FOErrorView.php"/>			
		</module>							
		<module id="PrivateModule" className="PrivateModule" classPath="private/PrivateModule.php">
			<view id="PrivateView" className="PrivateView" classPath="private/PrivateView.php"/>
		</module>		
		<module id="NewsModule" className="NewsModule" classPath="news/NewsModule.php">
				<view id="FONewsListView" className="FONewsListView" classPath="news/FONewsListView.php"/>
		</module>		
		<module id="UserModule" className="UserModule" classPath="user/UserModule.php"/>			
		<static id="MenuStatic" template="fo/menu/menu.tpl.html"/>	
		<static id="LoginFormStatic" template="fo/user/loginForm.tpl.html"/>		
		<static id="LogOutLink" template="fo/user/logoutLink.tpl.html"/>
	</modules>
	
	<profile role="anonymous" errorContainer="ErrorContainer" defaultContainer="MainContainer">		
		<container id="ErrorContainer" template="fo/error.tpl.html" alias="/error">
			<component moduleId="ErrorModule" viewId="FOErrorView" templateVariable="content"/>
			<static-component staticId="MenuStatic" templateVariable="menu"/>				
		</container>		
		<container id="RootContainer" template="fo/root.tpl.html">			
			<static-component staticId="MenuStatic" templateVariable="menu"/>
			<static-component staticId="LoginFormStatic" templateVariable="login_form"/>						
		</container>				
		<container id="MainContainer" template="fo/defaultContainerTemplate.tpl.html" parentContainer="RootContainer" templateVariable="content">
			<component moduleId="NewsModule" viewId="FONewsListView" templateVariable="content"/>
		</container>									
		<container id="LoginContainer" template="fo/defaultContainerTemplate.tpl.html" alias="/login" parentContainer="RootContainer" templateVariable="content">
			<static-component staticId="LoginFormStatic" templateVariable="content"/>
		</container>					
		<actions></actions>
	</profile>
	
	<profile role="user" errorContainer="UserErrorContainer" defaultContainer="UserMainContainer">		
        ...
	</profile>
</project>
компилится в PHP файл:
PHP:
<?php
global $projectDescriptor;
$projectDescriptor = new ProjectDescriptor();

.....
$moduleDescriptor = new ModuleDescriptor();
$moduleDescriptor->id="NewsModule";
$moduleDescriptor->className="NewsModule";
$moduleDescriptor->classPath="news/NewsModule.php";
$moduleDescriptor->viewList=array();
$viewDescriptor = new ViewDescriptor();
$viewDescriptor->id="FONewsListView";
$viewDescriptor->className="FONewsListView";
$viewDescriptor->classPath="news/FONewsListView.php";
$moduleDescriptor->viewList[]=$viewDescriptor;
$projectDescriptor->moduleList[] = $moduleDescriptor;

.....
и передается Engin-у ри создании того.
PHP:
...
$engine = new ProjectEngine($projectDescriptor, $context, $templateEngine, $db);
$engine->handleRequest();
...
6) Идея
- MVC
- возможность реюзания модулей (с дописыванием к ним новых view классов по необходимости)

7) Размышления
Это один из вариантов MVC архитектуры которую можно реализовать на PHP
Нечто подобное жавовского Tapestry, например, имхо не сделаешь просто потому что будут жуткие тормоза
Struts? Проблема в реализации таглибов. А без них это совсем другое, и называется просто Model 2 :)

8) 2 Alexandre
>отсутствие повторного использования кода (чем страдают большинство WEB приложений)

это достоинство? или ты имел ввиду присутствие?

9) 2 All
Сорри за многословность, но мне интересна эта тема :)
 

Ямерт

The Old One
Предлагаю перенести топик в "PHP для профи" - пошли интересные мысли, которые по-моему уже не относятся к уровню новичков. Не хотелось бы, чтобы этот трэд затерялся среди "памагите" и "извените" :)
 

.des.

Поставил пиво кому надо ;-)
Не затеряется :) будет сохранена ссылка в Избранном.
 

Ямерт

The Old One
wrapper (OFFTOPIC) Struts и без таглибов рулит - если, например, использовать Velocity вместо JSP. Опять же, Velocity полезен с точки зрения архитектуры - кроме View ты туда ничего не впихнёшь при всём желании. А в JSP теоретически можно написать что угодно.
 

Alexandre

PHPПенсионер
это достоинство? или ты имел ввиду присутствие?
нет - я имел ввиду, что ранее мне приходилось на базе одной
CMS для реализации ее клонов делать черезмерно чаще операции PASTE/COPY и свя моя работа сводилась к устранению ошибок при переносе кода - что меня просто убивало.

Думаю в новой системе это здесь будет отсутствовать.

wrapper - просто отлично :)
чисто технический вопрос:
каким образом осуществляется
компилится в PHP файл:
и как часто?

над остальным я просто буду думать
 
Сверху