How to access Module model from within the console app

Hi,

I’ve successfully configured the Yii console app for sending perioding emails. Here is the working console.php config file.




<?php


// This is the configuration for yiic console application.

// Any writable CConsoleApplication properties can be configured here.

return array(

	'basePath'=>dirname(__FILE__).DIRECTORY_SEPARATOR.'..',

	'name'=>'Console Application',

	'import'=>array(

	    'application.models.*',

	    'application.components.*',

	    'application.modules.content.*',

	    'application.modules.content.models.*',

            'ext.yii-mail.YiiMailMessage',

	),

	// application components

	'components'=>array(

        'mail' => array(

            'class' => 'ext.yii-mail.YiiMail',

 	    'transportType' => 'smtp',

            'transportOptions'=>array(

                'host'=>'smtp.gmail.com',

                'username'=>'user@gmail.com',

                'password'=>'pass',

                'encryption'=>'ssl',

                'port'=>465,

            ),

 	    'logging' => false,

 	 ),

	'db'=>array(

 	    'connectionString' => 'mysql:host=localhost;dbname=mydb',

 	    'username' => 'root',

	    'password' => 'rootpass',

	    'emulatePrepare' => true,

	    'charset' => 'utf8',

	    'tablePrefix' => 'tbl_',

	    'enableProfiling' =>true,

            'enableParamLogging'=>true

	),

    ),

);



And I have this Command class.




class SendEmailCommand extends CConsoleCommand

{

    public function actionComments()

    {

        // located at /protected/models/post.php

        $post = new Post;  // WORKS!


        // located at /protected/modules/content/models/settings.php

        // $settings = new Settings;    // This DOES NOT WORK <img src='http://www.yiiframework.com/forum/public/style_emoticons/default/sad.gif' class='bbc_emoticon' alt=':(' />


        echo 'Send Comment';

    }

}



I can run it with cronjobs (yiic sendemail comments) and it works fine. I can instantiate the model classes like Post (as you can see above) which is located under /protected/models. Everything is ok

But as you can also see, I cannot instantiate the models located within the modules. I receive an error which says: Send Commentexception ‘CException’ with message ‘Property “CConsoleApplication.settings” is not defined.’ in /home/user/yii/framework/base/CComponent.php:131

But I have correctly indicated in the config file to import all the




	    'application.modules.content.*',

	    'application.modules.content.models.*',



What can be a problem? I think there is something I’m missing.

Anyone? Anyone knows how to access Module models within the Console apps? I would appreciate very much if you could give me any clue.

That message looks like as if you are doing


Yii::app()->settings->...

somewhere within your console application?

Your config looks ok. Maybe you could post the complete stack trace for more info.

Hi. Thanks for the attention. Here is what.

The console app, successfully loads any model, be it root model or the one inside other modules. This is fine.

But I found another problem which is really strange, looks like a bug. Let me explain.

I am debugging the app right now. To remind, this is a console app which has only the following call.




class SendEmailCommand extends CConsoleCommand

{

    public function actionComments()

    {

        // located at /protected/modules/content/models/post.php

        $post = new Post;


        echo 'Send Comment';

    }

}



As you can notice, the Post model is moved into the "content" module. Well, this is ok. The Post model has the following relations.




class Post extends CActiveRecord

{

   ...

   public function relations()

   {

       return array(

           // User model is located at /protected/models/User.php

           'author' => array(self::BELONGS_TO, 'User', 'user_id'),

       );

   }

   ...

}



The User model, on the other hand, is located in the /protected/models/User.php, i.e. this is the root app model, not inside the module. When I access the site through the Web application and load the Post model, everything works fine - it successfully builds this relationship with the User model, and displays the site on the browser.

However, the BIG problem occurs when I access the Post model through the console app. For some reason it tries to get the component called "user", not the model. Here is the stack trace.




Send Commentexception 'CException' with message 'Property "CConsoleApplication.user" is not defined.' in /home/user/yii/framework/base/CComponent.php:131

Stack trace:

#0 /home/user/yii/framework/base/CModule.php(88): CComponent->__get('user')

#1 /home/user/protected/modules/content/models/Post.php(90): CModule->__get('user')

#2 /home/user/yii/framework/db/ar/CActiveRecord.php(2301): Post->relations()

#3 /home/user/yii/framework/db/ar/CActiveRecord.php(372): CActiveRecordMetaData->__construct(Object(Post))

#4 /home/user/yii/framework/db/ar/CActiveRecord.php(387): CActiveRecord::model('Post')

#5 /home/user/yii/framework/db/ar/CActiveRecord.php(62): CActiveRecord->getMetaData()

#6 /home/user/protected/commands/SendEmailCommand.php(13): CActiveRecord->__construct()

#7 [internal function]: SendEmailCommand->actionComments()

#8 /home/user/yii/framework/console/CConsoleCommand.php(135): ReflectionMethod->invokeArgs(Object(SendEmailCommand), Array)

#9 /home/user/yii/framework/console/CConsoleCommandRunner.php(63): CConsoleCommand->run(Array)

#10 /home/user/yii/framework/console/CConsoleApplication.php(88): CConsoleCommandRunner->run(Array)

#11 /home/user/yii/framework/base/CApplication.php(158): CConsoleApplication->processRequest()

#12 /home/user/yii/framework/yiic.php(33): CApplication->run()

#13 /home/user/protected/yiic.php(7): require_once('/home/user/prot...')

#14 {main}



I suppose this might be a bug, because there is no way to model to be treated as a component. Please help me figure out if this is a Yii bug, or there is a work around.

Strange, what’s on line 90 in Post.php?

Jackpot!!! That’s the line which causes the problem!


Yii::app()->user->isGuest ? 0 : Yii::app()->user->id

So, this is not a bug for sure! And there are two solutions I can use.

[list=1]

[*]Ignore the ActiveRecrod and use the DB class directly and make SQL queries manually to retrieve the necessary data.

[*]I don’t know if it is possible to “switch off” the relations loading, i.e. is it possible to force the model not to load the relations?

[/list]

I don’t know why you need this line, but it looks like the send mail command is there to send “system mails”, meaning $userId is always 0 in console? If that’s the case you can do:


(Yii::app() instanceof CConsoleApplication || Yii::app()->user->isGuest) ? 0 : Yii::app()->user->id

The actual problem is that CConsoleApplication does not have the user component (Yii::app()->user, CWebUser class). That’s why you get that error. It has nothing to do with any model or relation.

Yes, I understood that immediately when you pointed to the Line #90. And I don’t need user in the console app. The thing is the Web app uses the user, this is why I need that line any way. But if I could say to Yii not to load the relations I would continue my work. Is it possible? Otherwise, I will not use AR, but do direct SQL querying.

But this line is in Post.php not in the relation User.php. Means if relation load or not shouldn’t matter.


Yii::app()->user->isGuest ? 0 : Yii::app()->user->id

Why not simply add a condition around the "web only" code?


if (Yii::app() instanceof CWebApplication)

{

   // code only for web application

}

I think, this code is really nice to have. I will use it.

And I would like to thank you very much for your time. Otherwise, I am two days behind my plans. You saved me. Thank you!

Hey my suggestion,

rather than writing Yii::app() instanceof CConsoleApplication everywhere, why dont you just do the following:

  1. open config/console.php and set



'import'=>array(

		'application.models_console.*',

                'application.extensions.*',

	),



Note: I am not using models of my webapp, instead created a folder, which indeed contains the copy of models from my webapp, but only those which are required for my console app. and remove any line which is trying to access Yii::app and Enjoy :)

I had the same problem.

I just created new class that extend my model class, and override relation method. Also had usage of user module in afterFind method. Solved it with creating in regular model method




protected function afterFindConsole(){ 

 	parent::afterFind(); 

} 

and declared




protected function afterFind(){

 	parent::afterFindConsole();

}

in model for console.

Big Thanks! This was exactly what I needed!