Permalink
Browse files

feat(routes): use named routes in core

Rewrites page handlers using new named route API.
Updates some resource views with logic contained in removed page handler functions.
Deprecates the use of handler parameter in entity menus and removes it
for some core entities.
Add elgg_generate_entity_url().
Add elgg_generate_action_url().

Refs #11563
Fixes #9126
  • Loading branch information...
hypeJunction committed Jan 8, 2018
1 parent fe49ebf commit f04c3925c99817ec836046c3bb89c24128284a2d
Showing with 487 additions and 478 deletions.
  1. +0 −17 actions/comment/delete.php
  2. +2 −2 actions/login.php
  3. +20 −1 docs/appendix/upgrade-notes/2.x-to-3.0.rst
  4. +1 −1 docs/guides/actions.rst
  5. +24 −1 docs/guides/routing.rst
  6. +1 −1 engine/classes/Elgg/Application.php
  7. +1 −1 engine/classes/Elgg/FormsService.php
  8. +5 −2 engine/classes/Elgg/PasswordService.php
  9. +6 −2 engine/classes/Elgg/Router.php
  10. +4 −2 engine/classes/ElggEntity.php
  11. +0 −56 engine/lib/admin.php
  12. +1 −67 engine/lib/comments.php
  13. +0 −2 engine/lib/cron.php
  14. +4 −4 engine/lib/filestore.php
  15. +25 −15 engine/lib/navigation.php
  16. +105 −0 engine/lib/pagehandler.php
  17. +4 −79 engine/lib/users.php
  18. +0 −33 engine/lib/widgets.php
  19. +130 −64 engine/routes.php
  20. +11 −2 engine/tests/phpunit/unit/Elgg/ActionsServiceUnitTest.php
  21. +7 −1 engine/tests/phpunit/unit/Elgg/CronServiceTest.php
  22. +59 −1 engine/tests/phpunit/unit/Elgg/RouteMatchingTest.php
  23. +1 −2 languages/en.php
  24. +0 −25 mod/blog/start.php
  25. +0 −2 mod/blog/views/default/object/blog.php
  26. +10 −0 mod/profile/elgg-plugin.php
  27. +3 −71 mod/profile/start.php
  28. +8 −6 mod/profile/views/default/resources/profile/edit.php
  29. +10 −1 mod/profile/views/default/resources/profile/view.php
  30. +9 −8 views/default/core/avatar/upload.php
  31. +0 −1 views/default/object/comment.php
  32. +2 −0 views/default/resources/admin/plugin_text_file.php
  33. +8 −5 views/default/resources/avatar/edit.php
  34. +11 −0 views/default/resources/comments/view.php
  35. +1 −1 views/default/resources/phpinfo.php
  36. +14 −2 views/default/resources/widgets/add_panel.php

This file was deleted.

Oops, something went wrong.
@@ -43,9 +43,9 @@
// they provided.
elgg_get_session()->set('forgotpassword:hash_missing', get_input('username'));
$output = [
'forward' => 'forgotpassword',
'forward' => elgg_generate_url('account:password:reset'),
];
return elgg_ok_response($output, '', 'forgotpassword');
return elgg_ok_response($output, '', elgg_generate_url('account:password:reset'));
}
return elgg_error_response($result);
@@ -540,10 +540,11 @@ Removed actions
* ``import/opendd``
* ``discussion/reply/save``: See :ref:`upgrade-discussion-replies`
* ``discussion/reply/delete``: See :ref:`upgrade-discussion-replies`
* ``comment/delete``: Use ``entity/delete`` action
* ``uservalidationbyemail/bulk_action``: use ``admin/user/bulk/validate`` or ``admin/user/bulk/delete``
* ``uservalidationbyemail/delete``: use ``admin/user/bulk/delete``
* ``uservalidationbyemail/validate``: use ``admin/user/bulk/validate``
Inheritance changes
-------------------
@@ -716,6 +717,24 @@ are no widgets in the layout, you can now pass a special ``no_widgets`` paramete
When registering widgets you can no longer omit passing a context as the ``all`` context is no longer supported. You need
to explicitely pass the contexts for which the widget is intended.
Routing
-------
Page handling using ``elgg_register_page_handler()`` has been deprecated.
We have added new routing API using ``elgg_register_route()``, which allows plugins to define
named routes, subsequently using route names to generate URLs using ``elgg_generate_url()``.
See :doc:`routing </guides/routing>` docs for details.
As a result of this change all core page handlers have been removed, and any logic contained
within these page handlers has been moved to respective resource views.
``elgg_generate_entity_url()`` has been added as shortcut way to generate URLs from named
routes that depend on entity type and subtype.
Use of ``handler`` parameter in entity menus has been deprecated in favour of named entity routes.
Action responses
----------------
@@ -26,7 +26,7 @@ Actions must be registered before use. Use ``elgg_register_action`` for this:
The ``mod/example/actions/example.php`` script will now be run whenever a form is submitted to ``http://localhost/elgg/action/example``.
.. warning:: A stumbling point for many new developers is the URL for actions. The URL always uses ``/action/`` (singular) and never ``/actions/`` (plural). However, action script files are usually saved under the directory ``/actions/`` (plural) and always have an extension.
.. warning:: A stumbling point for many new developers is the URL for actions. The URL always uses ``/action/`` (singular) and never ``/actions/`` (plural). However, action script files are usually saved under the directory ``/actions/`` (plural) and always have an extension. Use ``elgg_generate_action_url()`` to avoid confusion.
Registering actions using plugin config file
--------------------------------------------
@@ -24,7 +24,7 @@ Page Handling
=============
Elgg offers a facility to manage your plugin pages via custom routes, enabling URLs like ``http://yoursite/my_plugin/section``.
You can register a new route using ``elgg_register_route()`, or via ``routes`` config in ``elgg-plugin.php``.
You can register a new route using ``elgg_register_route()``, or via ``routes`` config in ``elgg-plugin.php``.
Routes map to resource views, where you can render page contents.
.. code-block:: php
@@ -97,6 +97,29 @@ The following conventions are used in core and recommended for plugins:
- ``default:object:blog``: handle the generic path ``/blog``.
``<entity_subtype>`` can be omitted from route names to register global routes applicable to all entities of a given type.
URL generator will first try to generate a URL using the subtype, and will then fallback to a route name without a subtype.
For example, user profiles are routed to the same resource view regardless of user subtype.
.. code::php
elgg_register_route('view:object:attachments', [
'path' => '/attachments/{guid}',
'resource' => 'attachments',
]);
elgg_register_route('view:object:blog:attachments', [
'path' => '/blog/view/{guid}/attachments',
'resource' => 'blog/attachments',
]);
$blog = get_entity($blog_guid);
$url = elgg_generate_entity_url($blog, 'view', 'attachments'); // /blog/view/$blog_guid/attachments
$other = get_entity($other_guid);
$url = elgg_generate_entity_url($other, 'view', 'attachments'); // /attachments/$other_guid
Route configuration
-------------------
@@ -487,7 +487,7 @@ public function run() {
} catch (HttpException $ex) {
$forward_url = REFERRER;
if ($ex instanceof GatekeeperException) {
$forward_url = elgg_is_logged_in() ? '' : '/login';
$forward_url = elgg_is_logged_in() ? '' : elgg_get_login_url();
}
$hook_params = [
@@ -80,7 +80,7 @@ public function __construct(ViewsService $views, Logger $logger) {
public function render($action, $form_vars = [], $body_vars = []) {
$defaults = [
'action' => elgg_normalize_url("action/$action"),
'action' => elgg_generate_action_url($action, [], false),
];
// append elgg-form class to any class options set
@@ -76,9 +76,12 @@ function sendNewPasswordRequest($user_guid) {
$user->setPrivateSetting('passwd_conf_time', time());
// generate link
$link = _elgg_config()->wwwroot . "changepassword?u=$user_guid&c=$code";
$link = elgg_generate_url('account:password:change', [
'u' => $user_guid,
'c' => $code,
]);
$link = _elgg_services()->urlSigner->sign($link, '+1 day');
// generate email
$ip_address = _elgg_services()->request->getClientIp();
$message = _elgg_services()->translator->translate(
@@ -282,8 +282,12 @@ public function registerRoute($name, array $params = []) {
$defaults[$wildcard] = ''; // make it optional
}
if (array_key_exists($wildcard, $patterns) && !isset($requirements[$wildcard])) {
$requirements[$wildcard] = $patterns[$wildcard];
if (!isset($requirements[$wildcard])) {
if (array_key_exists($wildcard, $patterns)) {
$requirements[$wildcard] = $patterns[$wildcard];
} else {
$requirements[$wildcard] = '.+';
}
}
$segment = '{' . $wildcard . '}';
@@ -1204,9 +1204,11 @@ public function getTimeUpdated() {
* @return string The URL of the entity
*/
public function getURL() {
$url = _elgg_services()->hooks->trigger('entity:url', $this->getType(), ['entity' => $this]);
$url = elgg_generate_entity_url($this, 'view');
if ($url === null || $url === '' || $url === false) {
$url = _elgg_services()->hooks->trigger('entity:url', $this->getType(), ['entity' => $this], $url);
if (empty($url)) {
return '';
}
@@ -211,12 +211,6 @@ function _elgg_admin_init() {
// Add notice about pending upgrades
elgg_register_event_handler('create', 'object', '_elgg_create_notice_of_pending_upgrade');
elgg_register_page_handler('admin', '_elgg_admin_page_handler');
elgg_register_page_handler('admin_plugin_text_file', '_elgg_admin_markdown_page_handler');
elgg_register_page_handler('robots.txt', '_elgg_robots_page_handler');
elgg_register_page_handler('phpinfo', '_elgg_phpinfo_page_handler');
elgg_register_page_handler('admin_plugins_refresh', '_elgg_ajax_plugins_update');
}
/**
@@ -681,56 +675,6 @@ function _elgg_admin_page_handler($page) {
return true;
}
/**
* Formats and serves out markdown files from plugins.
*
* URLs in format like admin_plugin_text_file/<plugin_id>/filename.ext
*
* The only valid files are:
* * README.txt
* * CHANGES.txt
* * INSTALL.txt
* * COPYRIGHT.txt
* * LICENSE.txt
*
* @param array $pages URL segments
* @return bool
* @access private
*/
function _elgg_admin_markdown_page_handler($pages) {
elgg_set_context('admin');
echo elgg_view_resource('admin/plugin_text_file', [
'plugin_id' => elgg_extract(0, $pages),
'filename' => elgg_extract(1, $pages),
]);
return true;
}
/**
* Handle request for robots.txt
*
* @return true
*
* @access private
*/
function _elgg_robots_page_handler() {
echo elgg_view_resource('robots.txt');
return true;
}
/**
* Handle request for phpinfo
*
* @return true
*
* @access private
*/
function _elgg_phpinfo_page_handler() {
echo elgg_view_resource('phpinfo');
return true;
}
/**
* When in maintenance mode, should the given URL be handled normally?
*
@@ -19,9 +19,7 @@ function _elgg_comments_init() {
elgg_register_entity_type('object', 'comment');
elgg_register_action('comment/save');
elgg_register_action('comment/delete');
elgg_register_plugin_hook_handler('entity:url', 'object', '_elgg_comment_url_handler');
elgg_register_plugin_hook_handler('container_permissions_check', 'object', '_elgg_comments_container_permissions_override');
elgg_register_plugin_hook_handler('permissions_check', 'object', '_elgg_comments_permissions_override');
elgg_register_plugin_hook_handler('email', 'system', '_elgg_comments_notification_email_subject');
@@ -30,8 +28,6 @@ function _elgg_comments_init() {
elgg_register_event_handler('update:after', 'all', '_elgg_comments_access_sync', 600);
elgg_register_page_handler('comment', '_elgg_comments_page_handler');
elgg_register_ajax_view('core/ajax/edit_comment');
elgg_register_ajax_view('page/elements/comments');
elgg_register_ajax_view('river/elements/responses');
@@ -44,36 +40,6 @@ function _elgg_comments_init() {
elgg_register_plugin_hook_handler('prepare', 'notification:create:object:comment', '_elgg_comments_prepare_notification');
}
/**
* Page handler for generic comments manipulation.
*
* @param array $segments URL segments
*
* @return bool
*
* @access private
*/
function _elgg_comments_page_handler($segments) {
$page = elgg_extract(0, $segments);
switch ($page) {
case 'edit':
echo elgg_view_resource('comments/edit', [
'guid' => elgg_extract(1, $segments),
]);
return true;
break;
case 'view':
_elgg_comment_redirect(elgg_extract(1, $segments), elgg_extract(2, $segments));
break;
default:
return false;
break;
}
}
/**
* Are comments displayed with latest first?
*
@@ -172,38 +138,6 @@ function _elgg_comment_redirect($comment_guid, $fallback_guid) {
forward($url);
}
/**
* Format and return the URL for a comment.
*
* This is the container's URL because comments don't have their own page.
*
* @param string $hook 'entity:url'
* @param string $type 'object'
* @param string $return URL for entity
* @param array $params Array with the elgg entity passed in as 'entity'
*
* @return string
* @access private
*/
function _elgg_comment_url_handler($hook, $type, $return, $params) {
$entity = $params['entity'];
/* @var \ElggObject $entity */
if (!$entity instanceof ElggComment || !$entity->getOwnerEntity()) {
// not a comment or has no owner
// @todo handle anonymous comments
return $return;
}
$container = $entity->getContainerEntity();
if (!$container) {
return $return;
}
return "comment/view/{$entity->guid}/{$container->guid}";
}
/**
* Allow users to comment on entities not owned by them.
*
@@ -13,8 +13,6 @@
* @access private
*/
function _elgg_cron_init() {
elgg_register_page_handler('cron', '_elgg_cron_page_handler');
elgg_set_config('elgg_cron_periods', array_keys(\Elgg\Cron::$intervals));
elgg_register_menu_item('page', [
@@ -138,9 +138,6 @@ function _elgg_filestore_init() {
// Unit testing
elgg_register_plugin_hook_handler('unit_test', 'system', '_elgg_filestore_test');
// Handler for serving embedded icons
elgg_register_page_handler('serve-icon', '_elgg_filestore_serve_icon_handler');
// Touch entity icons if entity access id has changed
elgg_register_event_handler('update:after', 'object', '_elgg_filestore_touch_icons');
elgg_register_event_handler('update:after', 'group', '_elgg_filestore_touch_icons');
@@ -263,7 +260,10 @@ function elgg_get_inline_url(\ElggFile $file, $use_cookie = false, $expires = ''
* @since 2.2
*/
function elgg_get_embed_url(\ElggEntity $entity, $size) {
return elgg_normalize_url("serve-icon/$entity->guid/$size");
return elgg_normalize_url(elgg_generate_url('serve-icon', [
'guid' => $entity->guid,
'size' => $size,
]));
}
/**
Oops, something went wrong.

0 comments on commit f04c392

Please sign in to comment.