Thinking in Yii lifecycle

现在Yii的生命周期为

[list=1]

[*]通过 CApplication::preinit() 预初始化应用;

[*]设置类的自动装载器和错误处理;

[*]注册核心类组件;

[*]加载应用配置;

[*]通过 CApplication::init() 初始化应用:

  • 注册应用行为;

  • 载入静态应用组件;

[*]触发 onBeginRequest 事件;

[*]处理用户请求:

  • 解析用户请求;

  • 创建控制器;

  • 运行控制器;

[*]触发 onEndRequest 事件。

[/list]

在下以为,应予以修改为:

1,创建urlManager组件.

2,解析用户请求;

3,预初始化其它应用;

4,设置类的自动装载器和错误处理;

5,注册核心类组件;

6,加载应用配置,包括模块配置统一加载;

7,通过 CApplication::init() 初始化应用:

  • 注册应用行为;

  • 载入静态应用组件;

8,触发 onBeginRequest 事件;

9,处理用户请求:

  • 创建控制器;

  • 运行控制器;

10,触发 onEndRequest 事件。

之所以把创建urlManager组件,解析用户请求放在第一位,

是由于,在现在的周期流程之下,在模块中的配置不能一开始就和应用主配置同步。

运行状态下,模块的配置不起作用,不能覆盖主配置。

举个例子,

在主配置config中,设置了组件的属性,如果想在模块中,进行修改,preinit()或者init()中设置Yii::app()->setComponents($componentsConfig),或者Yii::app()->configure($config)都不能奏效。

拿urlManager来说,假如,主配置中设为path格式,模块要独立为get格式,通过以上方法,都不能奏效。

直接Yii::app()->urlManager->urlFormat='get’倒是可以,生成的链接不再是path格式,但点击时却不能有效解析,直接返回了没有参数的默认的控制器动作结果。

如果应用从用户请求开始,就能基于请求的模块加载配置,则问题会简单很多。

感觉现在Yii的执行流程和urlManager对url的控制解析,都需要改进。

基于这个问题,在这里提出粗浅的见解。至于具体方法,上面只是一个不成熟的建议。

表述中有不当,不详尽的地方,还望见谅。

正确与否,也望各位朋友和qiang哥莫怪。

这是个鸡和蛋的问题:URL的解析决定了使用哪个module;你又希望module能决定URL的解析。

在实践中,一个应用里的URL格式应该是统一的,而不应该让module来决定。module是从属于application的。

如果不同的module决定不同的URL解析方式,可能造成冲突。

假如原来的urlFormat为get,然后改为path,我希望原来的链接继续有效,但现在是无效的,对SEO可能不太好。

如果把创建urlManager组件,解析用户请求放在第一步,不论是get,还是path,现在也只有这两种,都能首先决定使用哪个module。继而就有可能依靠该module的配置决定接下来页面中链接生成的方式。也能配置其它专属于该module的其它配置。所以,这可以不必是一个鸡和蛋的问题,可以打另外一个比方,不管是皇帝,还是大巨,还是平民,不管是坐车,还是骑马,还是走路,他们都可以从一个城门进入,互不冲突。把创建urlManager组件,解析用户请求放在第一步,并不是由module决定url的解析,仍然由urlManager决定,只不过,这时urlManager必须自己识别urlFormat是get,还是path,而不是仅依靠config中的配置。module是从属于application的,但是在module应用中,module就是主角,module最大,可能需要重写application的配置。Yii::app()->setComponents($componentsConfig),或者 Yii::app()->configure($config),并不能够起这种作用,不论组件是urlManager,还是其它的,为何?是完全从属,还是一定程度的独立,这两者之间应该是可以均衡考虑的。多谢qiang百忙之中,关注到并回答这个问题。希望可以继续得到您的解惑答疑。

针对你的特定问题"如何让get的url继续有效":你可以考虑使用apache rewrite规则,对老的URL进行301重定向。

我不太理解两个问题:

  1. 怎么让url manager自己识别urlFormat是get还是path

  2. 在预先没有任何配置的情况下,如何让url manager正确判断出当前用户请求的是什么module(注意:你希望module可以更改url manager的配置)

1,直接从url中可以看出区别,再者,path有rules,get没有,可以从这两点判断。

2,当第一个问题解决了之后,就可以知道是什么module。在这里,不是预先没有任何配置,有url manager的配置。先初始化url manager的配置,再解析url,接下来再配置应用的其它部分。分成两步配置,但可以让module专有配置重写主配置。

这是否可行呢?

我们的设计初衷是尽量降低各种部件之间的耦合度。我们不希望对应用部件的特殊属性进行特殊处理。因为这样做虽然能解决一些实际问题,但它可能带来更多的副作用。

  1. 缺省情况下,path也可以没有rule。

URL规则是一种整体规则,它应该只由app来决定。就像走路的左右规则一样,不能让大家自己定义。这样做当然会丧失一些灵活性,但它也保证了规则的通用性。

允许module来更改url配置也会碰到其它问题,例如怎么在module外创建module内的URL (如果module不是当前module)。

关键是把工具用好了,细节上的问题是小事,能做出什么东西来是大事。seo没那么重要的,关键是能为用户提供有效的服务。不要本末倒置。

1,对于缺省没有rule的path形式,内部应该也能和get形式区别判断。当然,这比不判断要复杂。原先为get的形式,没有经过改写,无论如何都应该是有效的。现在urlFormat设为path,不能够正确解析,这也是直接套用配置中urlFormat带来的问题。

2,降低各种部件之间的耦合度,应该可以带来更灵活的定制性。现在,是牺牲一些灵活性。

如果,先初始化url manager,解析url,面对各种各样重写过的url,的确会有问题。有可能不知道是哪个module的。module各有各的url rules,可能冲突。解决的办法,可以把所有module的url rules在一个地方统一设置,这会增加url manager和各module的耦合度,但程度可以接受。也可以分别在各自内部设置,运行url manager时,读取所有这些配置。当然,设置时都应该避免冲突的可能性。这样也会产生另外一些不好的问题,处理上更复杂,性能上会更差。至于怎么在module外创建module内的URL,也可以在module外根据module专属的rules解决。再说,为什么要在module外创建它的url。创建时,应该都由它自身内部创建,解析才在外面进行。这些緾来绕去的,实现起来,可能不是太好看,降低可读性,也增加了出错的可能性。但对于没有经过重写的get形式的url,即使urlFormat设为path,也应该尽量予以支持。基于各种考量,可以先把各module定义各自内部url parse形式、规则这个问题放到一边。但是,是否可以把一开始加载各自除urlManager外的其它配置进行考虑。比如,clientScript组件,可能在某个module我希望用另外的形式,现在,在module preinit()、init()中提示只读,不能重写配置。我的理解,任何请求,都是面向特定module的,该module自身需求配置的权重就应该最大。这些都是使用过程中的一些感受看法,具体实现上,没有试验。有还没有想到的不妥,还望qiang哥不吝指出。

面向SEO只是一个方面,也可以出于其它原因的考虑而有这种需要。

请教,奇怪的问题

比如这里面提到的。

qiang哥,where are you now?

关于SEO的问题,我已经给出建议,让你修改htaccess来进行301重定向。

关于这个讨论,我们可以一直进行下去,但我觉得不大会有什么实质结果。

撇开各种利弊不谈,实际上,我们基本是不可能对目前的流程做你建议的修改的,因为这样会破坏兼容性。

而且,你的答复里也提到了新建议里的一些问题。我觉得,与其做修改而引入新的问题,还不如考虑怎么利用好现有的解决方案。你觉得呢?

对于稳定性和兼容性的考虑,是有道理的。qiang哥说得对,同意。对于这个问题,只是源于一些使用过程中的困惑和想法。作为Yii的开发者,qiang哥考虑问题更深入全面,更谨慎。感谢qiang哥悉心参与讨论。也许,没有绝对完美的框架,但Yii是一个非常非常好的框架,用过的人都知道。而且,可以肯定的是,以后会更加的强大。感觉现在社区氛围不是十分红火,是接触了解Yii的人还不是很多,还是大家都很忙?希望有更多的人参与讨论一些话题,更好地促进Yii的发展。再次感谢qiang哥的解惑答疑,备感荣幸。