Moving components to a different directory

Hello. I would like to put all my widgets in a separate directory. I tried to move them from 'protected/components/' to 'protected/widgets' and when calling the widget, I changed:

<?php $this->widget('application.components.MyWidget') ?>

to

<?php $this->widget('application.widgets.MyWidget') ?>

Sadly, this didn't work and Yii complained that it could not find MyWidget.php.

Is there any way to move widgets to a dedicated directory? I would like to separate them from the other components.

This should work, and it's a good practice if your application is very complicated.

Please try to Yii::import('application.widgets.MyWidget', true) and see what is the error.

Adding Yii::import did not alter the error message. Below I copy the full error. It says it can't find the file, but the file is there:



$ ls /var/www/apocalypse/awards/protected/widgets/WMainMenu.php 


/var/www/apocalypse/awards/protected/widgets/WMainMenu.php


Here is the relevant part of layouts/main.php:



<div id="mainmenu">


<? $this->widget('application.widgets.WMainMenu',array(


Here is the error:



<?php


PHP Error


Description





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


Source File





/var/www/apocalypse/awards/3rd-party/yii/framework/YiiBase.php(297)





00285:      * Class autoload loader.


00286:      * This method is provided to be invoked within an __autoload() magic method.


00287:      * @param string class name


00288:      */


00289:     public static function autoload($className)


00290:     {


00291:         // use include so that the error PHP file may appear


00292:         if(isset(self::$_coreClasses[$className]))


00293:             include(YII_PATH.self::$_coreClasses[$className]);


00294:         else if(isset(self::$_classes[$className]))


00295:             include(self::$_classes[$className]);


00296:         else


00297: include($className.'.php');


00298:     }


00299: 


00300:     /**


00301:      * Writes a trace message.


00302:      * This method will only log a message when the application is in debug mode.


00303:      * @param string message to be logged


00304:      * @param string category of the message


00305:      * @see log


00306:      */


00307:     public static function trace($msg,$category='application')


00308:     {


00309:         if(YII_DEBUG)





Stack Trace





#0 /var/www/apocalypse/awards/3rd-party/yii/framework/YiiBase.php(297): autoload()


#1 unknown(0): autoload()


#2 /var/www/apocalypse/awards/3rd-party/yii/framework/web/CBaseController.php(138): spl_autoload_call()


#3 /var/www/apocalypse/awards/3rd-party/yii/framework/web/CBaseController.php(152): createWidget()


#4 /var/www/apocalypse/awards/protected/views/layouts/main.php(53): widget()


#5 /var/www/apocalypse/awards/3rd-party/yii/framework/web/CBaseController.php(119): require()


#6 /var/www/apocalypse/awards/3rd-party/yii/framework/web/CBaseController.php(88): renderInternal()


#7 /var/www/apocalypse/awards/3rd-party/yii/framework/web/CController.php(593): renderFile()


#8 /var/www/apocalypse/awards/protected/controllers/SiteController.php(51): render()


#9 /var/www/apocalypse/awards/3rd-party/yii/framework/web/actions/CInlineAction.php(32): actionLogin()


#10 /var/www/apocalypse/awards/3rd-party/yii/framework/web/CController.php(265): run()


#11 /var/www/apocalypse/awards/3rd-party/yii/framework/web/CController.php(243): runAction()


#12 /var/www/apocalypse/awards/3rd-party/yii/framework/web/CController.php(225): runActionWithFilters()


#13 /var/www/apocalypse/awards/3rd-party/yii/framework/web/CWebApplication.php(335): run()


#14 /var/www/apocalypse/awards/3rd-party/yii/framework/web/CWebApplication.php(123): runController()


#15 /var/www/apocalypse/awards/3rd-party/yii/framework/base/CApplication.php(170): processRequest()


#16 /var/www/apocalypse/awards/index.php(11): run()


[/code]

Could you try the following code in your entry script file?



$app=Yii::createWebApplication($config);


Yii::import('application.widgets.WMainMenu',true);


$app->run();


From your callstack, the import statement you inserted was not executed.

I don't understand. The stack still looks the same. This is my entry script:



<?php





// change the following paths if necessary


$yii=dirname(__FILE__).'/3rd-party/yii/framework/yii.php';


$config=dirname(__FILE__).'/protected/config/main.php';





// remove the following line when in production mode


defined('YII_DEBUG') or define('YII_DEBUG',true);





require_once($yii);





$app = Yii::createWebApplication($config);


Yii::import('application.widgets.WMainMenu',true);


$app->run();





#Yii::createWebApplication($config)->run();


But the error looks the same (I copy it again below). I know for sure that the app is going to the entry script (e.g. as opposed to the browser giving me a cached page) because if I insert a die("Hello world") on the first line, I get what I'd expect. Btw, I have Yii version 1.0.3.

Here is the full error page:



<?php


PHP Error


Description





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


Source File





/var/www/apocalypse/awards/3rd-party/yii/framework/YiiBase.php(297)





00285:      * Class autoload loader.


00286:      * This method is provided to be invoked within an __autoload() magic method.


00287:      * @param string class name


00288:      */


00289:     public static function autoload($className)


00290:     {


00291:         // use include so that the error PHP file may appear


00292:         if(isset(self::$_coreClasses[$className]))


00293:             include(YII_PATH.self::$_coreClasses[$className]);


00294:         else if(isset(self::$_classes[$className]))


00295:             include(self::$_classes[$className]);


00296:         else


00297: include($className.'.php');


00298:     }


00299: 


00300:     /**


00301:      * Writes a trace message.


00302:      * This method will only log a message when the application is in debug mode.


00303:      * @param string message to be logged


00304:      * @param string category of the message


00305:      * @see log


00306:      */


00307:     public static function trace($msg,$category='application')


00308:     {


00309:         if(YII_DEBUG)





Stack Trace





#0 /var/www/apocalypse/awards/3rd-party/yii/framework/YiiBase.php(297): autoload()


#1 unknown(0): autoload()


#2 /var/www/apocalypse/awards/3rd-party/yii/framework/web/CBaseController.php(138): spl_autoload_call()


#3 /var/www/apocalypse/awards/3rd-party/yii/framework/web/CBaseController.php(152): createWidget()


#4 /var/www/apocalypse/awards/protected/views/layouts/main.php(53): widget()


#5 /var/www/apocalypse/awards/3rd-party/yii/framework/web/CBaseController.php(119): require()


#6 /var/www/apocalypse/awards/3rd-party/yii/framework/web/CBaseController.php(88): renderInternal()


#7 /var/www/apocalypse/awards/3rd-party/yii/framework/web/CController.php(593): renderFile()


#8 /var/www/apocalypse/awards/protected/controllers/SiteController.php(24): render()


#9 /var/www/apocalypse/awards/3rd-party/yii/framework/web/actions/CInlineAction.php(32): actionIndex()


#10 /var/www/apocalypse/awards/3rd-party/yii/framework/web/CController.php(265): run()


#11 /var/www/apocalypse/awards/3rd-party/yii/framework/web/CController.php(243): runAction()


#12 /var/www/apocalypse/awards/3rd-party/yii/framework/web/CController.php(225): runActionWithFilters()


#13 /var/www/apocalypse/awards/3rd-party/yii/framework/web/CWebApplication.php(335): run()


#14 /var/www/apocalypse/awards/3rd-party/yii/framework/web/CWebApplication.php(123): runController()


#15 /var/www/apocalypse/awards/3rd-party/yii/framework/base/CApplication.php(170): processRequest()


#16 /var/www/apocalypse/awards/index.php(14): run()


Hi,

may be check case-sensitive?

I don't understand your suggestion. The file name is exactly WMainMenu.php so the case is correct.

I don't understand why Yii::import doesn't seem to do anything. If I comment out the $app->run() part I still see nothing. So the Yii::import line is not giving any output. On the other hand, the fact that it doesn't give an error might mean something.

I just tried the following entry script:



<?php





// change the following paths if necessary


$yii=dirname(__FILE__).'/3rd-party/yii/framework/yii.php';


$config=dirname(__FILE__).'/protected/config/main.php';





// remove the following line when in production mode


defined('YII_DEBUG') or define('YII_DEBUG',true);





require_once($yii);





$app = Yii::createWebApplication($config);


Yii::import('application.widgets.WMainMenu',true);


#$app->run();


echo "Hello world";


#Yii::createWebApplication($config)->run();


If you run this, you see "Hello world", with no errors.

[/code]

Have you checked class name (case-sensitive)?

After the import() statement in index.php, please check class_exists('WMainMenu',false) to see if it is true or false. I suspect it is false. That would mean you don't have a class named WMainMenu in the class file.

Quote

Have you checked class name (case-sensitive)?

Ah! That's what it was! Yes, there was a typo in the class name. I fixed it and now it works. Thanks!