Proposal for Module Support

Hi

Built the webapp using Yii.bat, then added a module MiniMe

Issue : the MainMenu component generates the links based on the $this->controller but since the controller is now MiniMe all the built links are referenced from within the module. for example on page http://localhost/tes…ex.php?r=MiniMe

The home link is rendered like http://localhost/tes…niMe/site/index

Which leads to an error.

We almost need a "RootController" that will get switched to when rendering the main layout (so $this->controller is no longer the module controller but is now an application controller ie RootController). So when components are rendering links in the main layout they will do so properly. A developer should be able to classify a controller as the "RootController" in the configuration. The rootcontroller may or may not have an actions defined within it.

thoughts ?

nz

When you are creating a URL using createUrl(), make sure the route starts with '/' to avoid being prefixed with module ID.

Yup that works too  ;D

The webapp generator will need to be updated to reflect this. Did you want an issue created for this ?

nz

not now. There are many changes that need to be made to the yiic tool.

Right now, let's test this new feature in every aspect and make it as stable as possible.

Created a nested module MiniYu inside of MiniMe.



class MiniMeModule extends CWebModule


{


	public function init()


	{


		// this method is called when the module is being created


		// you may place code here to customize the module or the application


		$this->setModules(array("MiniYu"));


	}


}





Is that the correct way ?

Noticed that when going to http://localhost/tes…=MiniMe/Miniyu/ the default controller is not invoked. This appears to be due to CWebApplication::createController is called with a $route of “/” making the statement



		if($route==='')


			$route=$owner->defaultController;


ineffective. I also tried this with a second nested module and saw “//” being passed in (eg. http://localhost/tes…MiniYu/MiniMe2)

Also for a request like http://localhost/tes…e2/Default/test the route is “Default/test///” which does work but i think the extra slashes should be removed

nz

Thank you. Fixed.

Verified fixed,

BTW Is using the init the correct way to set submodules up (for example see code above for MiniMeModule class) ?

nz

Yes, that's the expected way.

You may also save module configuration in a file and call configure() in init() to load the configuration.

I'm trying to use a widget contained in a module.

<?php $this->widget('application.modules.TextEdit.components.TextEditor', array('id'=>'home1')); ?>

Is that the correct way to to it?

It throwing an error:

Quote

include(TextEdit.php) [<a href='function.include'>function.include</a>]: failed to open stream: No such file or directory
<?php


//config:


	'import'=>array(


		'application.models.*',


		'application.components.*',


		'application.extensions.*',


	),


	//...


	'modules'=>array('TextEdit'),


Edit: In the docs it sounds like module components are only supposed to be shared at the module level, but I'm don't see any other ways to go about this.

The widget creates an ajax edit-in-place box.  The JS it generates points the ajax to a controller that is also in the module, which also uses a model (in the module).

Why it is complaining about including TextEdit.php? The widget statement may only complain about TextEditor.php.

Is the widget statement called inside your module's code? If so, you should not use the alias 'application.modules…' something because in theory, you don't know where the module will be installed. You can define an alias inside your module to point to the base path of it.

A couple of things - Is it possible for a controller to know it is in a module ? Is it possible that the module name be able to be used as a part of the resolvable class for the Yii::import operation ?

For example my main application calls a module "MiniMe" to "setup" itself. The module then registers a class as a callback point when some action occurs. So the module "MiniMe" needs to be able to provide the main application a classpath for the callback object - like "MiniMe.callbacks.DoAction".

So now the application wants to invoke the callback so it does a Yii::import("MiniMe.callbacks.DoAction") (which should resolve to "application.modules.MiniMe.callbacks.DoAction").

Add a nested module inside of "MiniMe" called "MiniYu", its callback should be "MiniMe.MiniYu.callbacks.DoAction" which should resolve to "application.modules.MiniMe.modules.MiniYu.callbacks.DoAction".

It would be nice if the controller provided some function that would prepare the path so all you would need to do is call $this->packagePath . ".callbacks.DoAction"

where $this->packagePath = "application" if in the application and $this->packagePath = "MiniMe" if in the top level module and $this->packagePath = "MiniMe.MiniYu" if in a module contained inside another module.

Thoughts ?

nz

The controller has a 'module' property which points to the module instance if any.

An alias named 'module' is also provided which points to the currently active module's base path. Note, if the module is a submodule of another one, the 'module' alias will point to the submodule's base path when it is active.

Hi

The alias 'module' will work only if the module is the "active" module. In my case the active module could be a different module. Using the $this->module->id I should be able to create an Yii importable class string by : "application.modules." . implode(explode("/", $this->module->id), ".modules.").".callbacks.DoAction"

Thanks

nz

Ah, your right, so the widget loads, but then it complains about the model called within the widget.

The widget is called outside of the module, and within the main app (so there no question if it is active/unactive).

This is where the model is called in the widget that throws an error (even though I do have the model in modules/TextEdit/models/)

<?php


	 */


	public function init()


	{


		$model = TextEdit::model()->find("`namedId`='{$this->id}'");


		if (!Yii::app()->user->hasAuth(Group::ADMIN)) {


			if ($model)


				echo $model->contentDisplay;


			return;	


		}


		$this->registerScript();





		echo '<div class="textedit" id="'.$this->id.'">';


		


		if ($model)


			echo $model->getParsed('content');


		else


			echo '<p>'.$this->defaultMsg.'</p>';


		


		echo '</div>';


	}

Is the path modules/TextEdit/models in PHP include_path?

If not, in your module class' init() method, you can do the following:



Yii::import('module.models.*');


Which one would you recommend (i'm guessing the latter)?  And is there any way to make it automatic without separately setting every module to import automatically (the 'import' app setting)?

This does not work:

<?php


	public function init()


	{


		Yii::import('module.models.*');


		$model = TextEdit::model()->find("`namedId`='{$this->id}'");


//...

Quote

Alias "module.models.*" is invalid. Make sure it points to an existing directory or file.

Which revision are you using? and which branch?

latest revision, /branches/1.0/ (the one that gets the updates first)

Could you update again? I just verified that it works fine. BTW, the signature of init() should be init($config). And you should call parent::init($config).