ENVOS - MVC Framework

_RVK_

Новичок
ENVOS - MVC Framework

Думал, выкладывать или нет. Но решил что сторонний взгляд и оценка не помешают.

http://rvk.phpclub.net

Фичи:
- Полное разделение бизнес-логики и логики представления
- Встроенная ORM на основе паттерна ActiveRecord
- Валидащия данных
- Pre и Post Фильтры
- Дичпечерезация запросов
- Утилиты командной строки, для создания компонент
- Smarty, как базовый шаблонизатор
- PHP 5 only
 

ForJest

- свежая кровь
Я одного не понял - зачем в example 200Кб php.err.log? :).
В целом, полазив по классам могу сказать - ничего ни новаторского ни идейного.
Обычный фреймворк средней руки, начально-среднего уровня подготовки.
Автор уже знает умные слова а-ля фильтры, контроллер и синглтон и поэтому пихает их, видимо для тренировки, приклеивая к, в целом, процецурному дизайну кода.

Т.е. начинают прослеживатся какие-то потуги "делать ООП", но пока что явно видны запахи кода
- Одержимость элементарными типами (этим болеет множество проектов на PHP)
- Длинный список параметров (из-за, понятное дело процедурного стиля)
- Длинный метод и обильное использование временных переменных (тоже процедурный стиль)

Ничего заслуживающего внимания или изучения, кроме как в паталогоанатомических целях :).
 

zerkms

TDD infected
Команда форума
толком посмотреть не успел, но уже бросилось в глаза наличие хтмл-я в коде
pager.class

-~{}~ 07.01.06 13:54:

и ещё...

index.php:

если код:

$controller = MainController::getInstance();
$controller->exec();

поместить в какой нить фильтр и добавлять его самым последним, то

$filterManager->execPre(); и $filterManager->execPost();
заменятся на какой нибудь $filterManager->exec; и тогда реализация будет более похожей на классическую, имхо

-~{}~ 07.01.06 13:58:

ob_start();
$this->Smarty->display($this->TemplateDir.$this->Template);
return ob_get_clean();

повеселило... ;)
http://smarty.php.net/manual/ru/api.fetch.php
 

_RVK_

Новичок
zerkms
pager.class древний класс, написанный этак пару лет назад :) Здесь присутствует по энерции и вобщем то нигде не используется пока. Есть иде я встроить его функционал, но с механизмом я пока не определился.

поместить в какой нить фильтр и добавлять его самым последним
Смысл?

Да знаю я про фетч :) Почему здесь написал именно так уж и не помню. :)


ForJest
Я одного не понял - зачем в example 200Кб php.err.log
Так я же обещал полный код сайта :) Ошибки - неотьемлемая составляющая
(fixed. за одно убрал фалы документатора. Их все равно можно скачать отдельно)

Т.е. начинают прослеживатся какие-то потуги "делать ООП", но пока что явно видны запахи кода
- Одержимость элементарными типами (этим болеет множество проектов на PHP)
Соглавись, этот запах не такой уж дурно пахнущий. Здесь я пока не увидел жгучего желания где-то использовать объект вместо элементарного типа. Например класс baseDBModel можно разобрать на подклассы, и тогда убрать сразу и первый и второй запахи, но пока необходимости в этом я не ощущаю.
То же и третий запах. Пока есть более важные вещи, а применить "Выделение метода" можно в любой момент :) Тем более не так уж там много длинных методов

Ничего заслуживающего внимания или изучения, кроме как в паталогоанатомических целях
Я выложил проект именно для того, что бы послушать вот такие отзывы.
 

zerkms

TDD infected
Команда форума
поместить в какой нить фильтр и добавлять его самым последним

Смысл?
смысл в том что в отличие от смарти - в паттернах, насколько я их знаю и понимаю, нет пре- и пост- фильтров. есть просто фильтры, только в зависимости от того где:
- перед запуском цепочки далее
- после запуска цепочки
происходят какие то действия - они становятся или пре- или пост- и сразу же исчезают в принципе ненужные методы

-~{}~ 07.01.06 20:26:

чот я напутал фильтры с цепочкой обязанностей.... ;)))

хотя никто не запрещает реализовывать фильтры цепочкой...
 

_RVK_

Новичок
zerkms
В моей реализации фильтры действительно не различаются, на уровне базового класса. Отличия проявляются лишь в реализации конкретных потомков. Вот тут разница большая, ибо Pre фильтры не имеют доступа к контроллеру, а лишь к контексту. А Post фильтры, наоборот, могут получить доступ к любым данным, но смысла менять контекст у них уже нет. Все уже отработало. Осталось только попросить View отдать контент. Потому и разделены фильтры на 2 лагеря. Теория теорией а практика говорит что так удобнее. Соответственно если выпонять
$controller = MainController::getInstance();
$controller->exec();

в фильтрах, то нужно четко следить за тем, что бы фильтрам 'до' не нужен был объект диспечера, а филтры 'после', наоборот, не меняли что-то в надежде повлиять на действия контроллера. Надеюсь мысль понятна...

Потому то такое четкое разделение. Они и так реализованны цепочкой, только двумя :).
 

ForJest

- свежая кровь
_RVK_
Ясно. Ну не буду спорить :).
Просто убрав длинные списки параметров ты неизбежно получишь новые запахи - как-то группы данных, и убрав их скорее всего - классы данных.
Когда дойдёшь до запаха классы данных, то, возможно наконец-то появится нечто стоящее для рефакторинга.
Пока что я увидел что классы почему-то предпочитают есть параметры методов вместо своих собственных полей.
--------------
Ну в принципе, да. По сравнению в вонью от длинных списков параметров этот запах действительно ещё не различим :).
 

_RVK_

Новичок
ForJest
Я то уже учуял этот запах. У меня сейчас конструирование запроса идет в одном классе. Если приглядишься к коду, то увидишь разделение на блоки:
+++++++++++
//Методы
-----------------

По сути эти части можно выделить в отдельные классы, таким образом поручив конструирование частей запросов отдельным классам. А baseDBModel будет выступать в качестве сборщика. Но это на будующее. Пока слишком большой необходимости в таком рефакторинге не вижу.

Вообще, мне сначала понравилась объектная модель mojavi. И только позже я понял, что все беда mojavi как раз в этом. Во первых такое обилие классов сильно усложняет понимание, и время потраченное на черезмерное проектирование замедляет разработку.

Кстати обрати внимание на DBManager. Как оценишь такое решение? Тоже с первого взгляда подпадает под один из запахов "Посредник" кажется. Но другого, кароме как использовать паттерн Bridge, решения я не нашел.
 

.des.

Поставил пиво кому надо ;-)
Общие замечания по коду.
Стиль именования методов встречаются все возможные модификации:
MethodName()
getMethod()
get_method()
_get_method()
ABBRtoName()
NameToABBR()
Вот например строчка, яркий пример нелогичности (
$sql = Singletone::getInstance()->Context()->db->sql_buffer();

То же самое с переменными, и полями классов.


FilterManager
global $_PRE_FILTERS_ENABLE;
global $_POST_FILTERS_ENABLE;
Это зачем так сделано?

Вообще фильтры очень странные, все это разделение на пре и пост как то притянуто не? Все таки классические Intercepting Filters имхо гораздо более красивое решение.
Но это уже все-таки религиозный вопрос, так как смотреть по результатам удобства использования.
 

Rammstein

PHPClub::News
Почему бы всем пхп-клабом не объединиться, и не написать хороший framework? А то у каждого своё на уме, а по сути всё дублируется.
 

.des.

Поставил пиво кому надо ;-)
Rammstein у всего php клуба не хватает времени отнести избранное к вике (каюсь) :( да и понятие хороший fw очень расплывчато.
Будем ждать Zend Framework :) хе хе..
 

_RVK_

Новичок
.des.
тиль именования методов встречаются все возможные модификации:
Все дело в том, что некоторые части (в частности те что находятся в lib) были написаны давно, и совсем не для ENVOS. Пока они выполняют свои функции, и я их не трогаю. Постепенно они будут перекачевывать в core, и тогда я буду их рефакторить.

FilterManager
global $_PRE_FILTERS_ENABLE;
global $_POST_FILTERS_ENABLE;
Это зачем так сделано?
Что именно? global? Вообщем-то может логичнее передавать эти массивы как параметры конструктору, но это как бы массивы конфигурации. Мне показалось такое решение более оправданным.

разделение на пре и пост как то притянуто не
Я же сказал что как такового разделения нет. Это потомки одного класса. Но одни экземпляры делают одно, и им нужны одни данные, а вторые другое, и им нужны совсем другие данные. Пример:фильтр проверяющий авторизацию. Ему не нужен контроллер. мало того, он должен выполнится ДО того как контроллер будет создан, что бы определить имеет ли пользователь доступ к запрошенному Action и изменить module/action на, например, index/deny. Второй пример SqlListFilter. Этому фильтру нежен уже сгенерированный HTML что бы дописать снизу спиок запросов для дебага. Нужно быть уверенным что филтры получат то, что им нужно для работы. Именно поэтому и есть такое разделение.
Кстати кажется подобное реализованно в mojavi.

-~{}~ 07.01.06 17:29:

Почему бы всем пхп-клабом не объединиться, и не написать хороший framework
Ты читал басню "Лебедь, рак и щука"? ;)
 

.des.

Поставил пиво кому надо ;-)
Все дело в том, что некоторые части (в частности те что находятся в lib) были написаны давно, и совсем не для ENVOS. Пока они выполняют свои функции, и я их не трогаю. Постепенно они будут перекачевывать в core, и тогда я буду их рефакторить.
Ну все эти примеры до сих пор можно найти в core. lib я не смотрел.

Что именно? global? Вообщем-то может логичнее передавать эти массивы как параметры конструктору, но это как бы массивы конфигурации. Мне показалось такое решение более оправданным.
Ну как сказать, в core/context/ находятся три класса App, Context, Environment при помощи которых различные модули получают необходимые данные, и вместе с тем это глобал в конструкторе класса.

... Я же сказал что как такового разделения нет. Это потомки одного класса. Но одни экземпляры делают одно, и им нужны одни данные, а вторые другое, и им нужны совсем другие данные. Пример:....[skipped]
Угу, это до той поры пока какому либо из фильтров не понадобится и то и другое. В Вашем случае это будет два фильтра и мне непонятно зачем.
Тем более что фильтры у вас получают/передают данные не от передаваемых им параметров, а от классов контекстов (одиночек).

Пример фильтров, которые и пре и пост одновременно: TimingFilter, StatisticFilter (который регистрирует до запуска контроллера и пишет в html свой js код )

Классически это делается так.

PHP:
class Filter
{
	public function doFilter($filter_chain)
	{
		// do pre processing
			$filter_chain->doFilter();
		// do post processing

	}
}
 

_RVK_

Новичок
Ну все эти примеры до сих пор можно найти в core. lib я не смотрел.
Ах да... я как-то пытался переместить их в ядро, но отказался. Думаю в случае с пейджером и логером нужен другой механизм. Моя ошибка, надо было их вообще удалить из дистрибутива. Но класс БД (тот пример что ты привел) находится именно в lib. Опять же не трогаю, потому как в нем есть удобные средства отладки, placeholder-ы и тп. Но весь этот функционал нужно перемещать в BaseDBModel.

Ну как сказать, в core/context/ находятся три класса App, Context, Environment при помощи которых различные модули получают необходимые данные, и вместе с тем это глобал в конструкторе класса.
Согласен. Испоьзовать контекст было бы логичнее.

Угу, это до той поры пока какому либо из фильтров не понадобится и то и другое.
Так Post фильтрам доступно и то и другое...
Вообще прочитал сейчас это http://ru.sun.com/pdf/patterns/pattern7.pdf и немного не понял. Intercepting Filter это непрерывная цепочка, на конце которой находится контроллер. Либо у меня отличное (от других) понимание контроллера, либо я не могу понять КАК фильры перехватывают исходящие данные. Ведь эти данные появляются только после того как отработал контроллер.
 

itprog

Cruftsman
Посмотрел. Для начала неплохо, хотя многие паттерны реализованы не совсем так как должны.

PHP5 кажется используется только для того чтобы не передавать объекты по ссылке. Да и то встречаются конструкции с ссылками:

PHP:
final class Context extends Singletone  {
    function set_log(log $log) {
        $this->log = & $log;
    }
}
Далее:
PHP:
abstract class Singletone {
	protected function __construct($class = null) {
		static $instances = array();
                ...
	}
}
Static лучше вынести в сам класс. (ведь используем PHP5)

Уж очень большое количество абстрактных классов...Как и финальных классов, т.е. расширять путем наследования собственно нечего...

Ну плюс маленький недочет, имхо, вместо табов лучше использовать 4 пробела.
 

sakon

П..и.н..ок
[offtop in offtop] :)
_RVK_
Решил реализовать "завиральную идею Фаната"?
[end offtop]
 

_RVK_

Новичок
Вот немного дописал документацию про фильтры. Надеюсь теперь понятнее.
http://rvk.phpclub.net/index.php?module=Documentation&action=View&id=30

-~{}~ 08.01.06 02:00:

>реализованы не совсем так как должны.
Вот уж сори, а как должны? Помоему паттерны на то и паттерны, что не навязывают реализации. Но я буду признателен за уточнения :) Только более конкретные.
Да и то встречаются конструкции с ссылками:
Не так уж и часто :) Но признаю, бывает. От старой привычки не так просто избавится :)
tatic лучше вынести в сам класс.
А этот класс я честно скомуниздил из onPHP, о чем честно признаюсь :) Понравилась реализация, и я не стал изобретать велосипед. Потому как получилось бы все равно что-то подобное.
Уж очень большое количество абстрактных классов...Как и финальных классов, т.е. расширять путем наследования собственно нечего...
Так в том то и дело. Я придерживаюсь принципа, закрывать все что можно. В дальнейшем всегда можно ослабить защиту (c) Фаулер чтоли...
Ну плюс маленький недочет, имхо, вместо табов лучше использовать 4 пробела.
Вот за это извиняюсь. Возможно где-то не доглядел.
 

itprog

Cruftsman
Так в том то и дело. Я придерживаюсь принципа, закрывать все что можно. В дальнейшем всегда можно ослабить защиту (c) Фаулер чтоли...
Хм, к примеру, final class Pager extends Singletone, в нем есть вывод таблицы. А что если в проекте их надо будет заменить на дивы (<div>)? CMF в моем понимании что-то общее для каждого проекта, но при этом для каждого проекта это общее может изменяться.
 

_RVK_

Новичок
itprog
Я уже говорил про Pager. Это аттавизм, доставшийся по наследству. В следующей версии я его уберу, а функционал перенесу... еще не знаю куда...

Вообще есть идея реализовать что-то подобное include в Ruby. Там тоже нет множественного наследования, но классы можно включать друг в друга, и пользоваться методами включенных классов как своими. Нечто подобное у меня реализованно в DBManager играющего роль Bridge между Actions и BaseDBModel. Actions обращаются к методам DBManager, хотя, на самом деле выполняют методв потомков BaseDBModel.
Это я к тому, что реализовать функционал того же Pager в ActionController можно, но это лишний баласт для тех, кому пейджинг не нужен. а так, тому кому он нужен, делают $this->Include("Pager") и используют его методы как свои... Ну это так, лирическое отступление...

-~{}~ 08.01.06 02:29:

А насчет final. Возьмем к примеру MainController. Никто вообще не должен хотеть это класс наследовать. Если у тебя возникло такое желание, значит я что-то неверно спроектировал, или ты что-то неверно делаешь. Именно для этого и нужны фильтры, Actions, SuperActions.... Именно для того, что бы никогда не возникло желания лезть в лгику MainController и даже просто в index.php
 

Rammstein

PHPClub::News
2 _RVK_ & .des.
А почему бы и нет? :) Может создали бы что-нибудь инновационное ...
 
Сверху