brendanheywood / moodle-local_cleanurls

Lets drag Moodle's url structure into this century...
36 stars 24 forks source link

Routing without webserver config #116

Open FMCorz opened 6 years ago

FMCorz commented 6 years ago

This is not an issue, I'm just sharing that I've implemented cleanish URLs in my plugin without requiring the admin to change their web server configuration. I suspect that this is something that could be done with your plugin where router.php is simply the point of entry of all requests.

The way my stuff works is by using PATH_INFO, through slasharguments. If the server does not support it, then I have nothing to contribute here. But when it does, all rewriting could go through:

local/cleanurls/index.php/course/here/there/etc

There are a few hoops to jump through when using such URLs, as Moodle does not handle slasharguments so well in its single_select and other things components, but that may not affect you because of the hook in moodle_url::out.

The main of my code is here:

Where URLs are blocks/xp/index.php/where/you/want/to/go. It's very simplistic in its way of finding the matching route, it looks for simple regex matching and extracts the arguments required. In fact, a more interesting thing is the use of controllers but that's unrelated.

Note: If slasharguments is turned off, it fallbacks to blocks/xp/index.php?_r=where/you/want/to/go.

brendanheywood commented 6 years ago

thanks @FMCorz - while you are here: I've been meaning to introduce some plugin level custom plugin level callbacks so other plugins can declare it's own clean url routes. This gets tricky as the cleanurls isn't in core (yet?) so most plugins will never implement it, but I'd like to hear your thoughts on it and see what shape you think the api should take.

FMCorz commented 6 years ago

I think the simplest way is for your plugin to use core_component::get_plugin_list_with_class, where by convention a plugin needs to define the class component\local\cleanurls\definition_maker or so which is implementing an interface for returning the information your API needs. Then you'd hook those options in list_child_options or something like this I suppose.

One of the amazing benefits of being able to set, and override, URL definitions would be for a local plugin to override Moodle's default implementation of any page. In fact, that may be even more useful for themes. They would effectively have a clean way to replace any PHP entry point.

brendanheywood commented 6 years ago

This plugin does already expose hooks which other plugins can then implement, we started with allowing course formats to specify their part of a url between the course prefix and the activity suffix. I don't think I would in core a way for any local plugin to arbitrarily modify any other part of moodles routes, each plugin should be responsible for it's own routes. This plugin does try to fill the gap in the middle but it's been a fairly hairy ride getting this far and we've jumped through an awful lot of hoops and we are still finding more edge cases.

FMCorz commented 6 years ago

Correctly me if I'm wrong, but you do not have hooks. What I found were classes, in your plugin, which hardcoded the behaviour of some course formats. This is far from a hook as only plugins which have been added to your plugin can effectively have an impact on the URLs. What I suggested was to allow any plugin to define their own URLs through a public API.

This plugin does try to fill the gap in the middle but it's been a fairly hairy ride getting this far and we've jumped through an awful lot of hoops and we are still finding more edge cases.

I don't see many more hoops ahead. If you allow plugins to define their URLs, and offer them an API to get the moodle_url they need, then it's done. Plugins will just need to specify a dependency on your plugin, that's all.

Now, an idea solution is to what #117 suggests. Which is what I talk about in my first comment. A proper routing system which invokes controllers rather than including a view.php files.

brendanheywood commented 6 years ago

Yes there is a proper hook-ish system, eg for course formats it first looks for a class inside the plugin and then falls back to the ones inside this plugin:

https://github.com/brendanheywood/moodle-local_cleanurls/blob/master/classes/clean_moodle_url.php#L104

So to be clear I think it's wrong for any plugin to be able to change the urls of any other part of core or any other plugin, each should only be responsible for it's tiny bit. This local plugin is the exception and the intent is to only ever bridge to core urls in this plugin, and keep other 3rd party plugins that we have written containing their own code (which we have done with custom course formats). We want each 'thing' to only be responsible for it's small part of the url, so one url might touch several cleaner objects to construct a full clean url eg:

course  -> format -> activity    -> activity sub page
COMP100 -> /week1 -> /help-forum -> /did-you-turn-it-on-and-off-again

So we need a clean api for each type of plugin, formats, activities, etc which is what @roperto has implemented starting with formats but paving the way for a similar architecture for say an activity to declare it's own routes within it's scope. The forum is the first one I was going to tackle if we can find the time or sponsorship. What they are passed and what they return can be different.

Moving to a proper controller system is highly desirable, but practically would need to work side by side with all the legacy view.php and similar. I would love to see it but I'm not holding my breath.