diff --git a/.upgradenotes/MDL-83164-2024092002215993.yml b/.upgradenotes/MDL-83164-2024092002215993.yml new file mode 100644 index 00000000000..7594cfdb6b0 --- /dev/null +++ b/.upgradenotes/MDL-83164-2024092002215993.yml @@ -0,0 +1,57 @@ +issueNumber: MDL-83164 +notes: + core: + - message: > + When rendering a renderable located within a namespace, the namespace + will now be included in the renderer method name with double-underscores + separating the namespace parts. + + + Note: Only those renderables within an `output` namespace will be + considered, for example `\core\output\action_menu\link` and only the + parts of the namespace after `output` will be included. + + + The following are examples of the new behaviour: + + | Renderable name | Renderer method + name | + + | --- | + --- | + + | `\core\output\action_menu\link` | + `render_action_menu__link` | + + | `\core\output\action_menu\link_primary` | + `render_action_menu__link_primary` | + + | `\core\output\action\menu\link` | + `render_action__menu__link` | + + | `\core\output\user_menu\link` | + `render_user_menu__link` | + type: improved + - message: > + The following renderer methods have been deprecated from the core + renderer: + + + | method | + replacement | + + | --- | + --- | + + | `render_action_menu_link` | + `render_action_menu__link` | + + | `render_action_menu_link_primary` | + `render_action_menu__link_primary` | + + | `render_action_menu_link_secondary` | + `render_action_menu__link_secondary` | + + | `render_action_menu_filler` | + `render_action_menu__filler` | + type: deprecated diff --git a/lib/classes/output/core_renderer.php b/lib/classes/output/core_renderer.php index 7b201004858..16e50445090 100644 --- a/lib/classes/output/core_renderer.php +++ b/lib/classes/output/core_renderer.php @@ -40,13 +40,9 @@ use core\hook\output\before_html_attributes; use core\hook\output\before_http_headers; use core\hook\output\before_standard_footer_html_generation; use core\hook\output\before_standard_top_of_body_html_generation; -use core\output\action_menu\link as action_menu_link; -use core\output\action_menu\link_primary as action_menu_link_primary; use core\output\actions\component_action; use core\output\actions\popup_action; -use core\output\action_menu\filler as action_menu_filler; use core\plugin_manager; -use core\output\action_menu\link_secondary as action_menu_link_secondary; use moodleform; use moodle_page; use moodle_url; @@ -1304,7 +1300,7 @@ class core_renderer extends renderer_base { // We don't want the class icon there! foreach ($menu->get_secondary_actions() as $action) { - if ($action instanceof \action_menu_link && $action->has_class('icon')) { + if ($action instanceof action_menu\link && $action->has_class('icon')) { $action->attributes['class'] = preg_replace('/(^|\s+)icon(\s+|$)/i', '', $action->attributes['class']); } } @@ -1391,43 +1387,95 @@ class core_renderer extends renderer_base { } /** - * Renders an action_menu_link item. + * @deprecated Since Moodle 4.5. Will be removed in MDL-83221 + */ + #[\core\attribute\deprecated( + replacement: 'render_action_menu__link', + since: '4.5', + mdl: 'MDL-83164', + )] + protected function render_action_menu_link(\action_menu_link $action) { + \core\deprecation::emit_deprecation_if_present([$this, __FUNCTION__]); + return $this->render_action_menu__link($action); + } + + /** + * @deprecated Since Moodle 4.5. Will be removed in MDL-83221 + */ + #[\core\attribute\deprecated( + replacement: 'render_action_menu__filler', + since: '4.5', + mdl: 'MDL-83164', + )] + protected function render_action_menu_filler(\action_menu_filler $action) { + \core\deprecation::emit_deprecation_if_present([$this, __FUNCTION__]); + return $this->render_action_menu__filler($action); + } + + /** + * @deprecated Since Moodle 4.5. Will be removed in MDL-83221 + */ + #[\core\attribute\deprecated( + replacement: 'render_action_menu__link_primary', + since: '4.5', + mdl: 'MDL-83164', + )] + protected function render_action_menu_primary(\action_menu_link $action) { + \core\deprecation::emit_deprecation_if_present([$this, __FUNCTION__]); + return $this->render_action_menu__link_primary($action); + } + + /** + * @deprecated Since Moodle 4.5. Will be removed in MDL-83221 + */ + #[\core\attribute\deprecated( + replacement: 'render_action_menu__link_secondary', + since: '4.5', + mdl: 'MDL-83164', + )] + protected function render_action_menu_secondary(\action_menu_link $action) { + \core\deprecation::emit_deprecation_if_present([$this, __FUNCTION__]); + return $this->render_action_menu__link_secondary($action); + } + + /** + * Renders an action_menu link item. * - * @param action_menu_link $action + * @param action_menu\link $action * @return string HTML fragment */ - protected function render_action_menu_link(action_menu_link $action) { + protected function render_action_menu__link(action_menu\link $action) { return $this->render_from_template('core/action_menu_link', $action->export_for_template($this)); } /** - * Renders a primary action_menu_filler item. + * Renders a primary action_menu filler item. * - * @param action_menu_filler $action + * @param action_menu\filler $action * @return string HTML fragment */ - protected function render_action_menu_filler(action_menu_filler $action) { + protected function render_action_menu__filler(action_menu\filler $action) { return html_writer::span(' ', 'filler'); } /** - * Renders a primary action_menu_link item. + * Renders a primary action_menu link item. * - * @param action_menu_link_primary $action + * @param action_menu\link_primary $action * @return string HTML fragment */ - protected function render_action_menu_link_primary(action_menu_link_primary $action) { - return $this->render_action_menu_link($action); + protected function render_action_menu__link_primary(action_menu\link_primary $action) { + return $this->render_action_menu__link($action); } /** - * Renders a secondary action_menu_link item. + * Renders a secondary action_menu link item. * - * @param action_menu_link_secondary $action + * @param action_menu\link_secondary $action * @return string HTML fragment */ - protected function render_action_menu_link_secondary(action_menu_link_secondary $action) { - return $this->render_action_menu_link($action); + protected function render_action_menu__link_secondary(action_menu\link_secondary $action) { + return $this->render_action_menu__link($action); } /** @@ -3178,7 +3226,7 @@ EOD; ); // Create a divider (well, a filler). - $divider = new action_menu_filler(); + $divider = new action_menu\filler(); $divider->primary = false; $am = new action_menu(); @@ -3215,7 +3263,7 @@ EOD; ) . $value->title; } - $al = new action_menu_link_secondary( + $al = new action_menu\link_secondary( $value->url, $pix, $value->title, diff --git a/lib/classes/output/renderer_base.php b/lib/classes/output/renderer_base.php index 00910c3eaab..dc276135aaa 100644 --- a/lib/classes/output/renderer_base.php +++ b/lib/classes/output/renderer_base.php @@ -218,15 +218,29 @@ class renderer_base { public function render(renderable $widget) { $classparts = explode('\\', get_class($widget)); // Strip namespaces. - $classname = array_pop($classparts); + $classpartname = array_pop($classparts); // Remove _renderable suffixes. - $classname = preg_replace('/_renderable$/', '', $classname); + $classname = preg_replace('/_renderable$/', '', $classpartname); - $rendermethod = "render_{$classname}"; - if (method_exists($this, $rendermethod)) { - // Call the render_[widget_name] function. - // Note: This has a higher priority than the named_templatable to allow the theme to override the template. - return $this->$rendermethod($widget); + $rendermethods = []; + + // If the renderable is located within a namespace, and that namespace is within the `output` L2 API, + // include the namespace as a possible renderer method name. + if (array_search('output', $classparts) === 1 && count($classparts) > 2) { + $concatenators = array_slice($classparts, 2); + $concatenators[] = $classname; + $rendermethods[] = "render_" . implode('__', $concatenators); + } + + // Fall back to the last part of the class name. + $rendermethods[] = "render_{$classname}"; + + foreach ($rendermethods as $rendermethod) { + if (method_exists($this, $rendermethod)) { + // Call the render_[widget_name] function. + // Note: This has a higher priority than the named_templatable to allow the theme to override the template. + return $this->$rendermethod($widget); + } } if ($widget instanceof named_templatable) { @@ -250,6 +264,8 @@ class renderer_base { $context = $widget->export_for_template($this); return $this->render_from_template($template, $context); } + + $rendermethod = reset($rendermethods); throw new coding_exception("Can not render widget, renderer method ('{$rendermethod}') not found."); }