Warning: Cannot use a scalar value as an array in /home/admin/public_html/forum/include/fm.class.php on line 757

Warning: Invalid argument supplied for foreach() in /home/admin/public_html/forum/include/fm.class.php on line 770
Форумы портала PHP.SU :: Версия для печати :: Система управления контентом
Форумы портала PHP.SU » » CMS и фреймворки » Система управления контентом

Страниц (1): [1]
 

1. KorolevSerge - 23 Февраля, 2012 - 22:26:45 - перейти к сообщению
Итак, как известно, каждый программист однажды задумывается о написании своей CMS. Кто-то пишет, кто-то нет. Я решил попробовать, ибо на своем велосипеде ездить удобнее, чем на чужом. Улыбка

Имеем на данный момент
Точка входа index.php
Класс Application с единственным публичным методом run(), вызываемом из индексного файла
PHP:
скопировать код в буфер обмена
  1. Application::getInst('site')->run();
  2. // или
  3. Application::getInst('admin')->run();

В этом методе описан основной жизненный цикл приложения.
1. Инициализация сессий.
2. Инициализация роутера и разбор URL. Урлы могут быть в виде get-параметров или "человеко-понятные". Роутер определяет имя контроллера, действие (которое нужно выполнить) и представление (которое будет задействовано для отображения данных).
3. Запуск контроллера и получение от него представления.
4. Рендеринг и вывод.

Класс Controller. Остальные контроллеры наследуются от этого класса.
В нем имеются базовые методы аутентификации и финальный метод execute().
Пример из контроллера админки
PHP:
скопировать код в буфер обмена
  1. final public function execute()
  2. {
  3.         // Здесь мы получаем имя действия кторое запрашивает пользователь
  4.         // Значение передается GET или POST методом
  5.         // (index.php?ctrl=users&action=save)
  6.         // либо вычисляется роутером из SEF URL
  7.         // плюс проверки безопасности.
  8.         $action = $this->getAction();
  9.  
  10.         // Выполняем действие, если есть доступ в админку,
  11.         // или логинимся, или разлогиниваемся.
  12.         if (F::getUser()->hasPermissions('access_admin')
  13.                 || ($action == 'actionlogin')
  14.                 || ($action == 'actionlogout'))
  15.         {
  16.                 $this->$action();
  17.         }
  18.         // В противном случае переключаемся на шаблон страницы логина.
  19.         else {
  20.                 F::Session()->logout();
  21.                 $this->template_entry_point = 'alogin';
  22.                 $this->actionDisplay();
  23.         }
  24.         return $this->getView();
  25. }


ну и например расширение Users - управление пользователями.

PHP:
скопировать код в буфер обмена
  1. class UsersController extends Controller
  2. {
  3.         protected function save()
  4.         {
  5.                 $data = Request::getPOST();
  6.                 $this->getModel()->save($data);
  7.                 $this->setRedirect('index.php?ctrl=users&action=display&view=list');
  8.         }
  9. }


Правильно ли я сделал реализацию модульности системы?
2. digi - 23 Февраля, 2012 - 22:39:55 - перейти к сообщению
простой пример ;) допустим есть сайт со следующей структурой:

1) Главная
2) О компании
2.1) История
3) Новости

Предположим юзер запросил страницу, подпадающую под паттерн роутинга:
/news/{year}/{mon}/{name}.html

в результирующей странице требудется отобрадить в меню выделенным пунет "Новости".

также надо отображить хлебные крошки например так Главная > Новости > 2012 > Февраль > Первая новость.

ну а основном блоке конечно надо отобразить сам текст новости Улыбка

как сделать? ;)))
3. KorolevSerge - 23 Февраля, 2012 - 22:54:00 - перейти к сообщению
как отобразить текст понятно Улыбка роутер разберется что нужно вывести
а с меню и крошками пока не знаю что делать...
4. digi - 23 Февраля, 2012 - 23:08:04 - перейти к сообщению
во во Улыбка) а это самое интересное ;))

в общем, если есть желание предлагаю присоедениться к разработке фреймворка на базе компонентов Symfony 2 Улыбка
5. sKaa - 23 Февраля, 2012 - 23:19:21 - перейти к сообщению
Я не понял :
Зачем классу Application, который одновременно ещё и singletone публичный метод run если он только, что и делает это вызывает route..
Ты пытался разделить модели виды и контроллеры, а в итоге у тебя всё в куче. Application::getInst()->run(); каким-то чудом должен определять модель. Это вообще как?
Зачем внутрь родительского класса контроллера пихать авторизацию когда это уже модель? Выходит вы контроллером модель наследуете. Я понимаю, что инкапсуляция сложная фигня - но зачем так всё усложнять?

ИМХО удобней на мой взгляд делать HMVC нежели MVC.
Хм, гляди...
PHP:
скопировать код в буфер обмена
  1.  
  2. // Примитивно - но думаю понятно...
  3. try {
  4.         Application::delegate(
  5.                         array(
  6.                                 'controller' => Application::Route(0) ? Application::Route(0) : 'index',
  7.                                 'action' => Application::Route(0) ? Application::Route(1) : 'index',
  8.                                 'arguments' => Application::Route()
  9.                         )
  10.                 );
  11. }catch(Exception $e){
  12.         Application::delegate(
  13.                         array(
  14.                                 'controller' => 'error',
  15.                                 'action' => 'index',
  16.                                 'arguments' => array('errmsg'=>$e->getMessage())
  17.                         )
  18.                 );
  19.  
  20. }
  21.  

В классе Application..
1) Публичный статичный метод Route() // Он будет парстить URL, возвращая его в удобном виде, массив или может ещё что...
2) Публичный метод Delegate() // В качестве аргументов можно ему передать массивом название контроллера, действия и остальных аргументов..
Этот метод должен проверять наличие файла контроллера, действия в нём, создавать класс контроллера и выполнять call_user_func_array(array($controller, $action), $arguments);
Вышеуказанная конструкция поможет запускать из одного контроллера другой контроллера. Что нам теперь мешает внутри контроллера index index() вызвать аналогичный код, только уже с аргументом для функции delegate (array('contrller'=>'help' .. ));
В этом и ключевое отличие MVC от HMVC


Если не найден файл контроллера или действие в нём или ещё что-то пошло не так то сразу-же плевать исключением и будете автоматически переадресованы на Controller_Errror->Index($e->getMessage(), // сюда можно аналогично пихнуть всё остальное, чтобы потом внутри контроллера Error логировать или выводить ошибки.);

Далее уже внутри контроллера нужно создать класс View который и будет отвечать за рендеринг и вывод )) Да и модели все должны быть созданы внутри контроллера.

Короче я не трезв, давай сам думай.. Я чувствую, что не могу мысли сформулировать ))
6. KorolevSerge - 23 Февраля, 2012 - 23:59:48 - перейти к сообщению
sKaa пишет:
Зачем внутрь родительского класса контроллера пихать авторизацию когда это уже модель?
не авторизацию а методы-действия (action) login и logout
в этих методах вызывается базовая модель и авторизация происходит там.
sKaa пишет:
Выходит вы контроллером модель наследуете.
ни в коем случае )
sKaa пишет:
Публичный статичный метод Route()

У меня есть класс Router который занимается парсингом URL и обратной операцией - формирование SEF URL. Т.е. у него есть метод ::_, возвращающий примерно следующее
PHP:
скопировать код в буфер обмена
  1. Router::_('index.php?ctrl=users&view=profile&id=1'); //  '/users/profile/Sergey'

Роутер также проверяет наличие собственных роутеров расширений (компонентов, модулей, как хотите назовите)и при наличии возвращает результат их работы. Это для более гибкого формирования урлов, в зависимости от потребностей конкретного расширения. Например, базовое преобразование выглядит так, как на примере выше, а расширение Users может переопределить его сделать урлы такими:
PHP:
скопировать код в буфер обмена
  1. Router::_('index.php?ctrl=users&view=profile&id=1'); //  '/users/Sergey'

т.е. Application->run() выглядит примерно так
PHP:
скопировать код в буфер обмена
  1. public function run()
  2. {
  3.         $session = $this->getSession();
  4.         // ...
  5.         Router::parseURI(URI::current());
  6.  
  7.         // Запуск контроллера
  8.         try {
  9.                 $controller = $this->getController(Router::get('controller_name'));
  10.                 $view = $controller->execute();
  11.         }
  12.         catch (E_DB_ConnectError $e) {
  13.                 log_write($e->getMessage());
  14.                 die('Database connection error.<br/>');
  15.         }
  16.         catch (E_Bad_URL $e) {
  17.                 header($_SERVER['SERVER_PROTOCOL'] . " 404 Not found");
  18.                 header("Location: " . URI::root() . '/404.php');
  19.                 die();
  20.         }
  21.  
  22.         // Тут проверяется установлен ли редирект контроллером
  23.         // Если да то перенаправляем пользователя
  24.         $this->redirect();
  25.  
  26.         // Render
  27.         // ... некоторый код, я опущу
  28.         $html = $view->render();
  29.         echo $html;
  30. }

(Добавление)
в принципе то же самое, только роль метода ::Route выполняет отдельный класс, а роль :Голливудская улыбкаelegate из вашего примера возложена на $this->getcontroller()
7. sKaa - 24 Февраля, 2012 - 01:31:40 - перейти к сообщению
KorolevSerge, flow найден - это хорошо, но вот утерян разум.
действия пользователя должны быть методами внутри самого контроллера (допустим контроллер Index )
URL: http://hostname/login - должно запустить контроллер login, т.к вторым параметром мы ничего не передаём по умолчанию действием будет index. т.е URL hostname/login тоже самое, что и hostname/login/index
А выполнить delegate должен
call_user_func_array(array($controller, $action), array()); если за пример взять вышеуказанный юрл hostname/login/index
call_user_func_array(array('Controller_Login', 'Index'), array());

URL: http://hostname/login/logout
all_user_func_array(array('Controller_Login', 'Logout'), array());

У вас нет четкого представления MVC, и что такое Controller-Action в частности!
Зачем вы их наследуете сразу всеми контролерами?
Ещё раз повторяю: User в данном случае модель.
PHP:
скопировать код в буфер обмена
  1. <?
  2. class Controller_Index {
  3.         public function Login(){
  4.                 // ессно User - паттерн синглтон
  5.                 $User = User::getInstance();
  6.                 $User->Login(... сюда можно POST передать...);
  7.                 if(!$User->Auth()){
  8.                         // Хотя лично для меня это кажется говнокодом - (я выше писал, что я не трезв и возможно я и вправду не вижу очевидных плюсов ваших методов),  но у вас там жизненный цикл поэтому надо что-то вернуть контроллеру в ваш цикл.
  9.                         return $User::getError();
  10.                 } else {
  11.                         ....
  12.                
  13.                 }
  14.         }
  15.  
  16.         public function Logout(){
  17.                 $User = User::getInstance();
  18.                 if(!$User->Auth()){
  19.                         $User->Logout();
  20.                 }
  21.         }
  22. }


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

KorolevSerge пишет:

Router::_('index.php?ctrl=users&view=profile&id=1'); // '/users/Sergey'

Внимание! Вот теперь вы мне вряд-ли докажите, что Router::_('...') - не является моделью т.к скорей всего он дергает это данные из базы или ещё откуда..

Ну как минимум можно быть сделать контроллер Users и вот тут нас и выручит инкапсуляция...

PHP:
скопировать код в буфер обмена
  1.  
  2. abstract class Controller_Base {
  3.         public function __call($fn, $args){
  4.                 $this->Index($fn, $args);      
  5.         }
  6. }
  7.  
  8. final class Controller_Users extends Controller_Base {
  9.         public function Index(){
  10.                 list($username, ...) = func_get_args();
  11.                
  12.         }
  13. }
  14.  


Таким образом если отключить ваш модель-роутер, сделать, нормальный метод delegte - о чем я говорил выше. Итак если URL содержит /users/%USERNAME%
То в любом случае отработает Controller_Users->Index(%USERNAME%); Мы просто передадим имя пользователя как аргумент в действие контроллера, а он уже обратившись к модели решит, что там будет дальше!!!
8. KorolevSerge - 24 Февраля, 2012 - 01:52:15 - перейти к сообщению
sKaa, спасибо за мысли, нужно переварить информацию. Улыбка
по поводу роутера не совсем согласен, но пока разберусь с контроллерами, потом еще раз изложу свое видение роутера.
9. sKaa - 24 Февраля, 2012 - 01:59:44 - перейти к сообщению
Не благодари )
10. digi - 24 Февраля, 2012 - 02:16:43 - перейти к сообщению
KorolevSerge, вы читали документацию по Symfony 2?

по мне так такие вещи как Symfony\Component\Routing сделан более чем достойно и придумывать свой вариант не имеет смысла, а вот продумать реализацию паттерна MVC используя как можно больше готовых, отлаженных и распространённых решений это хорошая идея ;))

собственно предалагаю обсудить именно этот вопрос ;) в принципе с радостью готов поделиться своими наработками, хотя там мысли больше как "заметки для себя", но готов ответить на все вопросы ;)

 

Powered by ExBB FM 1.0 RC1