Хочу поделиться с комьюнити модулем controller, который можно взять здесь. В чем смысл модуля?
Модуль позволяет для каждого УРЛа, который вы определяете в hook_menu() прописать действие контроллера. Для этого есть специальный новый элемент 'action':
<?php
/**
* Implements hook_menu().
*/
function controller_menu() {
$items = array();
$items['admin/settings/controller'] = array(
'title' => 'Controller settings',
'action' => 'SettingsController::indexAction',
'access arguments' => array('access administration pages'),
);
return $items;
}
?>
Здесь объявляется новый контроллер SettingsController и действие indexAction() которое будет вызывано для УРЛа 'admin/settings/controller'.
По умолчанию контроллеры должны лежать в специальной папке controllers/. Которую можно создать в папке своего модуля. Имя файла будет таким же как и прописано в 'action', однако имя класса нужно дополнять префиксом, который будет равен имени модуля после применения СamelCase нотации (с первой большой буквой). Звучит сложно, чтобы понять какие префиксы добавятся для разных модулей, несколько примеров:
my станет My
test_my_super станет TestMySuper
и т. д.
В примере выше, в хуке меню объявлен контроллер SettingsController, имя модуля controller, значит полное имя класса будет ControllerSettingsController, а имя файла SettingsController.php. Пример как все это дело работает можно найти в самом модуле.
Надеюсь, понятно описал, если есть вопросы, спрашивайте!
P.S. У темы появилось продолжение.
Комментарии
Забыл сказать что action это обычный callback, который может возвращать либо строку, либо константы MENU_NOT_FOUND, MENU_ACCESS_DENIED, MENU_SITE_OFFLINE. Если это строка, она будет выведена на странице. Короче принцип тот же что и для обычных функций-обработчиков УРЛ'ов, которые прописываются в hook_menu().
В итоге получаем контроллеры страниц аля Zend Framework и прочие фреймворки.
в чём профит?
Судя по readme, для каждого элемента массива, возвращаемого hook_menu нужно указывать метод из класса, т.е. нельзя просто задать
<?php
$items['example'] = array(
'action' => 'MyController',
...
...
...
...
);
?>
чтобы для урла example вызывался MyController::indexAction
а для example/test MyController::testAction
и т.д. все автоматически как это сделано в популярных фреймворках
Если так и есть, не понимаю, чем будет такой подход удобней использовать. В итоге получаем все равно недопиленное ООП. Или я невнимательно ридми читал?
Не понятно, зачем это? Разве для урлов через хук_меню нельзя определить свои действия?
Еще по теме http://www.drupalprometheus.org/
Спасибо, очень интересная идея, можно изменить модуль, чтобы он поддерживал такое поведение. Правда не знаю всем ли это нужно? Тем что я выложил, пользуюсь и я сам и нашел это удобным, поэтому собственно и решил выложить. Вообще над идеей стоит подумать.
Если у вас сложный проект, очень удобно хранить множество связанных обработчиков путей в одном классе-контроллере, вот какие преимущества здесь:
1. Все обработчики меню лежат в одной папке.
2. По имени файла можно сказать что файл обрабатывает, например: AdminSetttingsController - понятно что это настройки админки какие-то.
3. Ну и получаем возможность наследоваться от какого-то вашего базового контроллера.
Вот кратко что может дать модуль (возможно, это не все, это так, сразу что пришло в голову).
Вам нужен фреймворк? Ставьте Yii\Symfony. Друпал -- не фреймворк и никогда им не станет.
Это и так без проблем реализовывается.
То же самое. Я сохраняю себе mymodule.adminpages.inc и использую module_load_include - стандартный Drupal-way
Вот это единственное, что может быть полезным. Но не составляет труда отдельно объявить класс внутри модуля и инициализировать его уже внутри калбкека.
Я понял, что вы имеете дело с фреймворками и хочется в друпале видеть некоторые их плюшки и удобности, но как раз самое вкусное в друпале реализовать и проблемно (подружить с доктриной, твигом, отключить родную систему прав и заменить на свою и т.д.), а выдумывать модуль, который просто позволяет в качестве калбека назначить метод из своего класса - ИМХО, пустая трата времени. Друпал такой каков он есть. Не идеален, но окуенен!
kyky, посмотрите на Друпал 8 и папку core/includes, многие вопросы отпадут.
boneg, реализовать можно все без проблем, нравится писать по-старинке - пишите. Те же кому интересно продвигаться вперед, смогут найти для себя полезное и интересное.
Интересно, чтобы вы сказали, если бы этот пост был о Доктрине? Наверное примерно так: "Вы привыкли у удобностям Доктрины, но можно все делать стандартными средствами Друпала, зачем изобретать велосипед?".
Для всех остальных скажу, что это решение, кстати, можно развить неплохо, например, сделать так, чтобы контроллеры и их действия сканировались автоматически и добавлялись без объявления в хуке меню. Но это в TODO.
Да при чем тут по-старинке? Если мне нужен напильник - я беру напильник, а не переделываю отвертку под напильник. И оставляю возможность без всякого опасения передать сайт другому разрабу, если на меня упадет кукурузник, т.к. все ответы на возникшие вопросы он сможет найти на api.drupal.org
Вы прекрасно знаете что при открытии страницы вы все равно инициализируете весь могучий друпал, а не только ваш + базовый контроллеры (как это сделано в фреймворках), а в нем уже подгружаете нужные модели и виды. Т.е. выигрыша в производительности вы не получите никакого. В чем тогда смысл? Кода ведь не меньше получится.
То что Drupal развивается как framevork - это и так понятно
Но вот то, что людям сложно перестроить свое мышление - просто огорчает
Либо ваши проекты слишком просты, либо вы полагаетесь на то, что на api.drupal.org описывается логика вашего приложения.
Смысл возникает, когда появляется сложность. Когда у вас в системе > 10 типов нод и в одном модуле вам нужно работать с ними.
Я бы еще добавил здесь: видим чужое, а свое нет.
Да при чем тут перестроить мышление? Мне приходится работать не только с друпалом. И я счастлив был бы если б в друпале переписали хотя бы класс работы с формами так, как сделано в Yii (имхо, самый удобный подход для работы с формами).
Просто реализация модуля в таком виде, в каком вы ее предлагаете, особой пользы при разработке не сделает. Хотя может вы собираетесь добавлять в него новые плюшки и фичи из популярных фреймворков, тогда прошу меня извинить, хотелось бы увидеть что сможет модуль спустя несколько версий, может действительно сделает разработку более привычной.
Не возражаете, если я в таком случае сделаю несколько предложений чего еще хотелось бы увидеть в модуле, который приблизит друпал к популярным фреймворкам?
Я хочу, чтобы меня правильно поняли. Я не стараюсь приблизить Друпал к фреймворку какому-либо, я хочу сделать его удобнее. Мне приходилось часто искать новые решения, чтобы разделить ответственности в сложном модуле. В основном модуль controller расчитан конечно на разработку приложений для предприятий и сложных модулей.
Я бы хотел увидеть ваши предложения, с удовольствие бы почитал...
Я использую немного другую концепцию
но смысл тот же http://www.drupal.ru/node/73058
Занятно, что в обоих топиках народ спрашивает "зачем это?" и обламывается -- гуру не соизволят привести развернутый пример.
Да, к друпалу можно прикрутить свои контроллеры, сделать что-то вроде фреймворка внутри CMS, но это уродливое решение.
Ну первое - это подключение контроллеров с автоматическим выбором метода и аргументов метода исходя из адреса, как мы обсуждали выше и как сделано в модуле, на который дал ссылку sas@drupal.org
Еще очень хорошая плюшка, которую я первый раз увидел в ASP.net-фреймворках, потом в PHP-фреймворке PRADO - функция генерации ссылки-экшна. Т.е. что-то вроде друпальной l(), но в качестве аргументов принимает HTML ссылки и экшн. Т.е. при переходе по ссылке юзера возвращает на ту же страницу, с которой он кликнул, при этом выполняется экшн.
Многие подобные реализации решаются в друпале сабмитом скрытой формы, которая отправляется при клике на ссылку, но я вам скажу, что просто задать экшн в урле намного удобней, не нужно лезть в JS и генерировать доп.формы.
Добавить загрузку видов внутри любой функции. Как-нить так было бы отлично:
<?php
$params = array();
$params['my1'] = 'dsfsfsf';
$params['my2'] = 'dfsdfsdf';
$params['my3'] = array('dfsdfsdf', 'fsdfsd', 'sdfsdg'); $view = new viewClass;
$view->loadView('ИМЯ_ВИДА.tpl.php', $params);
?>
В итоге в нашем ИМЯ_ВИДА.tpl.php имеем $my1 , $my2, $my3 и делаем нужную разметку. По-моему, хорошо расширит друпальную шаблонизацию привычным для фреймворков способом.
Прикрутить какой-нить обширный класс для генерации html (очень приличный в Symfony). Т.е. имеем функции:
doctype() - принимает в качестве аргументов 'xhtml', 'transitional', 'html5' и т.д.
tag(), open_tag(), close_tag() со всеми их наворотами и внедрением js. Получаем отлично читаемый понятный код. У меня кстати есть одна такая наработка для CodeIgniter - там скудный родной класс, я содрал самое нужное с Symfony и под себя его расширил. Скажу, очень удобно колдовать стало.
Добавить полезные небольшие классы из того же умирающего CodeIgniter - user_agent,Zip Encoding и т.д. Приятные мелочи, часто помогающие в работе.
Ну а много чего другого интересного просто не получится без вандальных правок ядра друпала(( Все же не все свои функции он дает перекрыть.
Если б был такой готовый модуль, который это все в одну кучу собирает - это был бы самый первый доп. модуль, который я подключал бы при разработке очередного проекта)).
Вообще я использовал этот подход, когда работал с Zend Framework и тогда мне как раз хотелось, чтобы пути можно было прописывать в комментах PHP. Для Друпала это можно реализовать так:
Контроллеры сканируются автоматически и из PHP комментов определяется путь и разрешения, например, пусть у нас есть метод fooAction контроллера BarMyController.
<?php
class BarMyController {
/**
* path /hello/world
* access callback my_function
* access arguments array('administer site configuration')
*/
function fooAction() {
return "Hello World!";
}
}
?>
Тогда в $items этого модуля, которые возвращает hook_menu(), добавилось бы автоматом:
<?php
$items['hello/world'] = array(
'action' => 'BarMyController::fooAction',
'access callback' => 'my_function',
'access arguments' => array('administer site configuration'),
);
?>
этот код бы уже преобразовался бы дальше в другой массив, понимаемый Друпалом (это как сейчас работает модуль controller).
Что-то я не очень понял: для любого пути ссылки можно прописать в hook_menu() элемент соответствующий, чтобы юзера вернуло на ту же страницу, можно сделать примерно так:
<?php
l(t('edit'), 'node/'. $node->nid .'/edit', array('query' => drupal_get_destination()))
// в обработчике пути потом сделать
function some_path_handler() {
// ...
drupal_goto();
} ?>
Можете раскрыть тему чуть подробнее, меня это заинтересовало, но я очевидно не понял о чем речь.
Это можно реализовать. До сих пор я вызывал функции темизации из контроллера и пока вроде все было ок. Как вариант можно реализовать этот подход. Тогда можно было бы ввести соглашения по именованию директорий, чтобы все не валялось в куче как сейчас это имеет место быть для большинства модулей.
Хорошо, ваши наработки могут пригодиться В качестве варианта предлагаю два:
1. Отдельная ветка Друпала 6 (с ориентиром на ветку Друпал 8), которая будет вводить ООП/MVC фичи.
2. Отдельный модуль.
Вот фичи, которые я предлагаю ввести:
controllers - контроллеры
libs/ - библиотеки, используе только этим модулем
models/ - сущности системы
nodeapi/ - все что связано с хуком nodeapi
ui/ - шаблоны + функции темизации
tests/ - тесты
utils/ - утилиты
services/ - сервисы
repos/ - репозитарии
Кстати у меня есть собственная наработка - ветка Друпала 6, где все это реализовано. Только надо конечно там подчистить все. Единственное требование это PHP >= 5.3. Могу поделиться если кому-то интересно. Если не интересно, можно часть требований оформить в виде модуля, скажем с названием mvc, который будет зависеть от модуля controller.
Как пример что можно расширить в nodeapi(). Многие часто пишут в hook_nodeapi():
if ($op == 'foo') {}
else if ($op == 'bar') {}
// и т.д.
}
это дело упрощается (реализация не моя, но я ее взял для своих проектов тоже):
<?php
/**
* Implementats of hook_nodeapi().
* Calls a new custom hook_nodeapi_{$op}_{$node->type}($node, $a3, $a4) for all modules.
*/
function myak_nodeapi(stdClass $node, $op, $a3 = null, $a4 = null) {
$hook = 'nodeapi_' . $op . '_' . $node->type;
foreach (module_implements($hook) as $module) {
$function = $module . '_' . $hook;
$function($node, $a3, $a4);
}
}
?>
Таким образом теперь можно для модуля 'foo', операции insert и типа 'test' будет такая реализация:
<?php
function foo_nodeapi_insert_test($node, $a3, $a4) {
}
?>
Таких вещиц множество, вроде мелочь, а удобно (IMHO).
Вот все это дело можно либо в ветку отдельную, либо в модуль. Но цель одна - собрание воедино удобств, которые реально упрощают жизнь разработчику.
Да, конечно.
Мы имеем класс myClass с методом myMethod, и имеем функцию для генерации экшн-ссылки, например act_link().
выводим print act_link('Йа ссылко', 'myClass::myMethod'), при клике на ссылку переходим на какой-нить /actions/myClass_myMethod (по этому адресу выполняется экшн) и мгновенный редирект на $_SERVER['HTTP_REFERRER'];
Т.е. имеем возможность генерировать экшн-ссылки для своих функций. Очень удобно.
boneg, спасибо, так понял
В общем все кто хочет увидеть нормальную поддержку ООП и что-то похожее на DDD (Domain Driven Design) с поддержкой модульного тестирования на базе PHPUnit в Друпал 6, следите за проектом на GitHub. Я не гарантирую что я реализую ее, но по крайней мере хочу воплотить свои представления об этом.
Это форк Drupal 6, название форка Myak. Будут правки ядра и модулей, чтобы добавить автозагрузку классов, а также убрать ошибки в распространяемых модулях. Уровень ошибок будет E_ALL ^ E_DEPRECATED, минимальная версия PHP - 5.3. По-возможности это будут минимальные правки, чтобы минимизировать изменение Друпала, для возможности последующего перехода на Drupal 8 или более старшие версии (Drupal 7 не рассматривается).
Пока первый коммит это чистая версия Drupal 6.22, планирую вносить туда измения, свои наработки с нуля. Кто будет пользоваться проектом, или по крайней мере пробовать его запустить, если найдете баги, просьба пишите их здесь.
Что будет сделано в ближайшем будущем:
С чем связано название? Сразу вспомнился Леонид Каганов (очень популярный IT-юморист времен популярности fido) и его гаденькая сказочка "Хомяк-семимяк"...
"А хомяк и говорит: загадай желание, оторви мяк и скажи: «Летилетивертолеткверхузадомнапередкнизупередомназадфигпрочтешьтакуюхрень» И желание исполнится."
Мне оно приснилось.
Если это делается для своих сайтов — ради бога.
Если это делается для сайтов клиентов — вы им делаете настоящую медвежью услугу, изменяя поведение стандартных вещей и не пытаясь делать это через лоббирование изменений в ядро в D8. Вы отлично попортите нервы следующему поколению разработчиков, поддерживающих проект, а они вам карму.
Мне не интересно бороться за внесение изменений в Друпал 8. Мне интересно сделать CMS, которая будет удобна мне и другим разработчикам. Это форк, который может перерасти в отдельную CMS и который возможно никогда не будет работать на базе Drupal 8. Я сам занимаюсь ее поддержкой и все модули которые там есть, я контролирую сам.
Хочу уточнить мою политику: я понимаю, что если я пофиксю только те модули, которые есть в составе форка, другие могут не работать. Поэтому говорю сразу: форк не рассчитан на другие contributed модули, будут (могут) поддерживаться только те модули которые уже есть там, которые я сам смогу поддерживать, или которые добавятся в будущем. Я бы хотел обойтись минимальными правками, при этом не исключено, что в будущем, из форка выделится отдельная CMS, которая будет использовать самые классные (по-моему мнению) идеи из др. фреймворков/CMS. Я не гарантирую что я буду поддерживать форк или что эта CMS когда либо появится. Я просто хочу сделать то, что будет удобно мне, и если для кого это будет тоже удобно, это будет хорошо
И еще, пока CMS это планы, меня пока устраивает Drupal в чуть измененном состоянии (см. форк myak). Скорее всего CMS это мое стремление все переделать. Так что пока форк, а там посмотрим. И насчет модулей: др. contributed модули могут не работать потому как многие модули бросают исключения E_NOTICE (из-за того, что написаны для др. уровня контроля ошибок, в myak используется E_ALL ^ E_DEPRECATED). Я решаю это в своих проектах только правкой кода модуля. Естественно при этом, если модуль нужно будет обновить, то приходится правку применять опять. Другого варианта я пока не вижу. Мне нужны исключения и преобразование ошибок в них.
Ну пока на этом наверное хватит, все таки тема была про модуль controller
Если переписать часть ядреных модулей друпала через контроллеры это ведь увеличит производительность? Так как не позволит php в пустую лопатить код который при данном конкретном запросе вызван не будет, а если понадобится так его менеджер запросов загрузит по требованию, как это делает Yii.
А в прометее по видео касту так и не понял require_once для модуля все равно выполняется? Неужели нельзя отложить загрузку ровно до того момент когда класс реально понадобится?
хахаха. а дрис то и не знает, что контролеры решили бы проблему друпала раз и навсегда
это основной промох хуков
Это не критично. Загрузка нескольких классов вам погоды не сделает (если вы, конечно, не ИИ пишете). Если уж думать об оптимизации, то в плоскости БД.
Это намек на то, что структура базы не приведена в нормальную форму ?
Нормализация далеко не всегда является оптимизацией
Комично выглядит изобретение велосипедов, лучше бы топикстартер посмотрел на ctools и D8 до написания кода и этого поста.
...другим эта часть лишняя.
очередной «велосипедостроитель» без понимания что такое сообщество Drupal.
edit автору рекомендую почитать группу http://groups.drupal.org/wscci и там получить коструктивные предложения и критику
Вам в свою очередь рекомендую прочитать эту тему.
Могу вам сказать, что у каждого такое понимание может быть свое.
Однако за ссылку спасибо, почитаю что там есть.
andypost@drupal.org и еще, на что в ctools вы думаете стоит обратить внимание? Какую версию ctools вы предлагаете рассмотреть? Для какой версии Друпала?
ctools для текущей версии - drupal 7
а посмотреть там на page manager и систему реализации плагинов
Товарищи, кто заинтересован в модуле и его развитии, и имеет аккаунт на Друпале, просьба продвинуть модуль, застрял в sandbox
http://drupal.org/node/1389042
У темы появилось продолжение.
Очень рекомендую не тратить время, а лучше приложить свои знания MVC в drupal 8 иннициативах WSCCI & CMI - там как раз люди делают очень похожее решение используя компоненты симфони2
Архитектура очень подробно описана в http://www.unleashedmind.com/en/blog/sun/drupal-8-the-path-forward