Module and URL management

Module can be considered as a self-contained application within another application. As a result,. it also participates in URL parsing and creation.

In 1.x, all URL parsing and creation are done at the application level. Module has little control about that.

In 2.0, I’m thinking to let module control its own URL parsing and creation. In particular:

  • If application url manager is set as GET format, then module url manager is ignored
  • If application url manager is set as PATH format, then[list]
  • URL creation within the module will be handled by the module URL manager unless it is using GET format.
  • When parsing a URL, if the first segment in the path info is a module ID, then[list]
  • If the module URL manager is in PATH format, the corresponding module will handle the rest part of the URL parsing. For example, path info ‘comment/x/yz’ will be handled by ‘comment’ module’s url manager which sees ‘x/y/z’ as the path info.
  • Otherwise, the application URL manager will continue parsing the URL.

[/list][/list]

What do you think about this proposal?

This has the benefit of making URL rule management less centric and giving modules more freedom in determining what URL formats to use.

The main drawback is that the module ID is now hardcoded in the URLs. Do you think this is acceptable?

Why GET format should be different from PATH? Do you think we need to keep GET format in Yii2 (is it actually used)?

I don’t like hardcoding any part of URLs.

Generally I think module should be able to provide URL rules and application should be able to override these rules. This way one will be able to use full-blown module while customizing its URLs.

Currently this behavior can be achieved with something like:




'onBeginRequest'=>function($event){

  $route=Yii::app()->getRequest()->getPathInfo();

  $module=substr($route,0,strpos($route,'/'));

 

  if(Yii::app()->hasModule($module))

  {

    $module=Yii::app()->getModule($module);

    if(isset($module->urlRules))

    {

      $urlManager=Yii::app()->getUrlManager();

      $urlManager->addRules($module->urlRules);

    }

  }

  return true;

},



“Why GET format should be different from PATH?” – what do you mean? They’re different.

GET format is useful

  • in systems where pretty URLs are not needed, e.g., backend systems.
  • when the server configuration doesn’t support using PATH
  • during development to exclude bugs introduced by URL rules

A drawback of your solution is that it always places module URL rules as the lowest priority, which may not be true.

The proposed solution is to free you from writing the ‘onBeginRequest’ handler. Under the same URL prefix (as the module ID), the module has full freedom on determining how its own URLs should be handled.

By configuring a module URL manager to be GET, it can let application URL manager to take care of the URL management, which is the same as the current behavior.

qiang

I’ve confused PATH/GET formats with something else. GET is useful and we should leave it as it is.

As for modules and prefixes, there are both pros and cons.

Pros

— No need to write additional code.

— Module will not conflict with other modules since there’s “namespace” URL prefix.

Cons

— No way to use module w/o prefix. For example, page module can be used for URLs like "/about", "/toc", "/feedback".

— No way to override URLs determined inside of the module from application config.

If I’m wrong about cons part then I’m fully supporting this change.

If you configure module url manager to use GET format, then basically the module url manager is ignored. Everything is determined by the application URL manager. In this case, you can remove prefix and use whatever URL format as determined by the application url manager.

BTW, I think we should rename "urlFormat" to be "enablePrettyUrl" (or some better name) so that it is easier to understand.

For me the rewrite rules were always enough, but I would say this is a nice feature.

Couldn’t this be done in Yii 1.x also, if you would just write a custom UrlManager which can delegate URL parsing to modules, if they provide an interface for it?

Couldn’t this be handled by custom rewrite rules on application level, in combination with an automatic name mapping for modules (modules could have an $url property i.e.)?

Giving modules more freedom -> giving applications less freedom.

I think this merely gives the illusion of freedom.

In the end, what are you trying to accomplish with a module? A forum module, for example, provides a lot of complex functionality - the least of what it provides would be a few SEO optimized URLs.

I think as application developers, we can handle that bit ourselves?

mindplay

We can but let’s imagine a forum module. It provides something like 10 different URL routes.

In case of module-defined routes you can just plug it into your application and have a forum with good looking URLs. Additionally we can rewrite some URLs with application config.

Now we have to define routes in application config. That means at least copy-pasting from forum readme file.

You’re proposing the module provides default URL patterns, and you can override them with application config?

That would work, I suppose. I’m afraid it’s going to complicate the routing and make it slower though - it could be tricky in some situations, trying to determine which route overrides what route in the module.

Is it going to be worth it? Saving you the work of copying 10 lines of route configuration, doesn’t seem like a big deal to me - that’s a pretty minimal configuration process, and you probably have other things you need to configure in the first place, so you’re probably already copying something from a configuration template…

As I see this… it would not get slower or complicated… it would be the same like it was all written in one place (Yii 1.1.x)… only that this way rules would be more organized…

If someone wants to use it… it has this option… if not he can put it all in one place like now…

Finding the route would not be a problem… if we keep the idea that the first route found that satisfy the request is THE ONE…

Ah, so the application routes would always be searched first?

And any other matching routes defined by the module simply would never even be tried, because a matching route was already found.

Yeah, it sounds like that would work? :slight_smile:

I like this suggestion very much, it would be very helpful for several projects we have been working on lately.

+1 this would promote easier integration of modules into applications, actually I had searched how to do this in yii 1.1.x

URL management is essential feature in any webapp, now days URL’s used for various futures

i see yii2.0 handling URL in most versatile way is it Human Readable Url, or Seo optimized Bas64 Encoded url, or even GET+POST combination.

UrlManager should give api\access as easy as possible, and able to fast and understandable way to create any type of it.

Able to connect to UrlManager infrastructure a testUnit or other test, to fast check any changes lead to errors. Or even better separated configuration with collision detection and variants generation from sources, as we generate controller\view. All that on Gii-based idea.

little about shema, basic diagram in it im interested mostly in OtherObjecs that’s possible is extended of abstract urlmanager.

As i mentioned in another my topic maximum management to rapid development is one key to successful frame work.

Maybe we can do the process of processing URL by the module more explicit, for example:




'urlManager'=>array(

    'urlFormat'=>'path',

    'rules'=>array(

        'pattern1'=>'route1', // usual route

        'pattern2'=>array('route1', 'urlSuffix'=>'.xml', 'caseSensitive'=>false), //usual route

        'forum/*'=>array('class'=>'ForumModule'), //process route by ForumModule class

    ),

),



So having a route format like “‘forum/*’=>array(‘class’=>‘ForumModule’)” will allow to redirect URL processing to the module class for URLs which starts with ‘forum/’.

This way we can explicitly set what requests should be processed by module, without hardcoding it’s ID.

Another suggestion regarding URL manager - it would be good to have a ‘continueProcessing’ option for CUrlRule - which will allow to continue with other rules after current rule was processed.

It can be useful when we have some rule at the top which adds some default parameters or even transforms current request URL. This can simplify following rules if we have common parameters in all URLs.

I liked this approach, I had already hacked yii 1 to do this for a few of my "modules" I think as long as the framework will support creating module friendly urls (and obiously the module needs to be properly written to use this structure) then this is a good idea…

It would be nice, if modules could provide their own URL rules, but main configuration should always have highest priority. A hardcoded namespace for each module is a very bad idea. It would be a deal breaker for me, and break a lot of my existing projects.

Hope you find a good solution.

I agree that allowing modules to manage their urls would be very useful. I also agree with others who do not want to hard code module names into the urls and I think seb’s idea of a rule format that allows a certain path to delegate to a module is a good way around this.

I want say too that modules must manage their urls if they want. It’s very usefull and correct.

Another problem is naming. Some controllers within application may have the same names as the modules. How Yii will resolve the problem if there are controller with name ‘forum’ and module with name ‘forum’? May be any flag to point to certain behaviour?

first, thank you for the framework!!

I haven’t had time to pull 2.0 and check for myself but I really hope this isn’t off the table (defining routes inside module configuration). Anyone using Yii who finds themselves working on a REST host/client is looking for this feature.

I think that the generic REST API module case shows why this solution is more eloquent to have path definitions inside the module configuration than burying a custom class reference in the ‘urlManager’ section of the configuration file.

Thanks again!

-Woody