Command perso Yii - Communiquer avec model

Bonjour,

J’ai un gros souci et après plusieurs recherches, et plusieurs heures, je ne réussis pas à trouver la solution…

Je souhaite tout simplement créer une commande que je lancerais régulièrement à l’aide de cron.

J’ai donc créé un fichier cron.php :




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

define('YII_PATH', dirname(__FILE__).DIRECTORY_SEPARATOR.'../../../../library/Yii');

define('ROOT_PATH',dirname(__FILE__).DIRECTORY_SEPARATOR.'../../../..');

define('CUSTOM_COMMAND', dirname(__FILE__).DIRECTORY_SEPARATOR.'../../console');

require_once(YII_PATH.'/yii.php');


// we'll use a separate config file

$configFile=dirname(__FILE__).DIRECTORY_SEPARATOR.'/cronconfig.php';


// creating and running console application

$app = Yii::createConsoleApplication($configFile);

//$app->commandRunner->addCommands(YII_PATH.'/cli/commands');

$app->commandRunner->addCommands(CUSTOM_COMMAND.'/commands');

$app->run();






Un fichier de configuration (équivalent de console.php et main.php) cronconfig.php :





date_default_timezone_set('Europe/Paris');

mb_internal_encoding('UTF-8');

error_reporting(E_ALL  & ~(E_NOTICE | E_STRICT));


$root = realpath(dirname(__FILE__) .DIRECTORY_SEPARATOR.'..'.DIRECTORY_SEPARATOR.'..');


// Setup path aliases

Yii::setPathOfAlias('root', $root);

Yii::setPathOfAlias('library', $root . DIRECTORY_SEPARATOR . 'library');

Yii::setPathOfAlias('app', $root . DIRECTORY_SEPARATOR . 'library' . DIRECTORY_SEPARATOR .'App');

Yii::setPathOfAlias('compfront', $root . DIRECTORY_SEPARATOR . 'application' . DIRECTORY_SEPARATOR .'modules' . DIRECTORY_SEPARATOR . 'frontend' . DIRECTORY_SEPARATOR .'components');

Yii::setPathOfAlias('public', $root. DIRECTORY_SEPARATOR . 'public');

Yii::setPathOfAlias('temp', $root. DIRECTORY_SEPARATOR . 'temp');

Yii::setPathOfAlias('emailtemplates', $root. DIRECTORY_SEPARATOR . 'library'. DIRECTORY_SEPARATOR .'App' . DIRECTORY_SEPARATOR .'emails' );

Yii::setPathOfAlias('vendor', $root . DIRECTORY_SEPARATOR . 'library' . DIRECTORY_SEPARATOR .'Vendor');


//define('ROOT_PATH',dirname(__FILE__).DIRECTORY_SEPARATOR.'../../../..');

return array(

// This path may be different. You can probably get it from `config/main.php`.

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

    'name'=>'Cron',


    'preload'=>array('log'),


    'import'=>array(

        'application.components.*',

        'application.models.*',

    ),

// We'll log cron messages to the separate files

    'components'=>array(

        'log'=>array(

            'class'=>'CLogRouter',

            'routes'=>array(

                array(

                    'class'=>'CFileLogRoute',

                    'logFile'=>'cron.log',

                    'levels'=>'error, warning',

                ),

                array(

                    'class'=>'CFileLogRoute',

                    'logFile'=>'cron_trace.log',

                    'levels'=>'trace',

                ),

            ),

        ),


// Your DB connection

        'db' => array(

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

            'username'              => 'myDB',

            'password'              => 'myDBPassword',

            'enableProfiling'       => true,

            'charset'               => 'utf8',

            'schemaCachingDuration' => YII_DEBUG ? 0 : 86400000, // 1000 days

            'enableParamLogging'    => YII_DEBUG,

        ),

    ),


    'commandMap' => array(

        'AutoCron' => array(

            'class' => 'application.modules.console.commands.AutoCronCommand',

            'dbConnection' => 'db',

        ),

    ),

);

Mon fameux fichier de commande est le suivant AutoCronCommand.php :





class AutoCronCommand extends CConsoleCommand{




    public function run($arg){




        $user = User::model()->findByPk(31);

        $user->user_name = 'CHANGE RUN !!!';

        $user->save();

    }




    public function actionChangeName()

    {


        $user = User::model()->findByPk(31);

        $user->user_name = 'CHANGE METHOD';

        $user->save();

    }

} 

Mais… lorsque j’exécute :


 php ../frontend/config/cron.php AutoCron

Ca me retourne une erreur :


PHP Error[2]: include(User.php): failed to open stream: No such file or directory 

Pourtant j’ai bien importer TOUS les models via le fichier cronconfig.php… Je sais qu’il est appelé puisqu’une erreur dans celui-ci entraine une erreur.

Comment faire ? J’ai trouvé un post similaire sur stackoverflow mais il n’y a pas de réponse…

Je vous remercie

Bonjour,

Simple question : ton cron fait-il partie d’une application web plus conséquente ? Je cherche juste à savoir si tu utilises ce modèle User ailleurs et s’il fonctionne.

Et deuxième question : travailles-tu sur un environnement Windows ou Unix ?

Verifie le chemin de l’alias avec:


echo Yii::getPathAlias('application.models');exit;

juste avant


$app->run()

, et aussi avant l’appel à createConsoleApplication.

Si le chemin n’est pas bon, c’est un indice.

Sinon, la piste suivante est de nom de la classe dans le fichier (User ou user?)

Verifie aussi qu’il n’y ait pas plus qu’un ‘User.php’ (celui qui est chargé pourraît être invalide).

J’ai en fait cette arborescence :

Application

_api

_backend

_frontend

library

_App

__models

___activeRecord (où tous mes models sont placés)

J’utilise effectivement ce model, et tous les autres, à la fois dans backend, api et frontend et ils fonctionnent tous parfaitement…

Ils respectent la même syntaxe majuscule au départ.

Je travaille sur un Linux… Disons que pour le moment je n’essaie même pas de le lancer via cron mais directement et j’ai cette erreur, donc le cron va forcément soulever la même erreur.

Une idée ?..

J’ai essayé et le chemin n’est effectivement pas bon !.. Je pensais pas, c’est partout pareil dans mes main.php ou autres configurations.

Par contre, j’ai essayé de faire un nouvel alias dans cronconfig.php et je m’aperçois qu’en fait la classe Yii n’est pas reconnue :




PHP Fatal error:  Class 'Yii' not found in /var/www/vhost/application/modules/frontend/config/cron.php on line 14

Comment faire ?..

Donc c’est un très bon indice.

Il faut vérifier


echo YII_PATH.'/yii.php';exit;

just avant le require_once de cela.

Bon,

Il faut plus “copier” sur “yiic.php” que ‘index.php’.

Donc il faut inclure ‘yiic.php’:





// change the following paths if necessary

$yiic=dirname(__FILE__).'/../../yii/framework/yiic.php';

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


require_once($yiic);



Le chemin vers yii.php est bon !

DOnc maintenant… Plus d’erreur d’affichée mais… Ca ne fait rien du tout !

J’ai même mis une erreur exprès dans ma méthode et rien ne se passe, ça n’a pas l’air de passer dans ma commande maintenant :confused:

Heum… Je ne comprends pas le but…

J’ai fait un require_once de yiic.php et c’est “pire”. Ca me renvoie vers l’aide de Yiic…

Perso, je lances tous mes crons à l’aide d’une commande yiic.

Tu as fait un AutoCronCommand.

Donc logiquement, ‘autocron’ devrait apparraitre dans la liste.

En fait, je n’ai absolument pas l’arbo de base et mon fichier commande n’est pas placé dans le dossier des commandes.

Comme j’ai besoin d’appeler mes models j’ai créé un fichier de configuration perso cronconfig.php.

J’ai aussi créé une “ApplciationConsole” perso et y ai importé MES commandes :


$app = Yii::createConsoleApplication($configFile); 

$app->commandRunner->addCommands(CUSTOM_COMMAND.'/commands');

Ca fonctionne mieux maintnant. Le problème reste situé dans YiiBase.

Mes models étendent tous une base… Et YiiBase les appelle, problème… Pas du tout appelé au bon endroit :




PHP Error[2]: include(/var/www/vhost/application/modules/library/App/models/activeRecord/_base/BaseUser.php): failed to open stream: No such file or directory

    in file /var/www/vhost/library/Yii/YiiBase.php at line 401

Alors qu’elles sont, comme les models dans : library/App/models/activeRecord/_base

Comment faire pour que YiiBase appelle la base mais dans le bon dossier et non dans "application/modules/" ?

Sinon, peut être as tu une tout autre solution (autre arbo etc…) ?

[size="4"]AJOUT :[/size]

Ok, j’ai changé l’alias root dans cronconfig.php:




$root = realpath(dirname(__FILE__) .DIRECTORY_SEPARATOR.'..'.DIRECTORY_SEPARATOR.'..'.DIRECTORY_SEPARATOR.'..'.DIRECTORY_SEPARATOR.'..');

Il trouve enfin la base de mes models !

Mes bases elles étendent AppActiveRecord (qui étend elle-même CActiveRecord, enfin !)

Cette classe est dans library/App/ar… Faut encore que je fasse un petit mapping qq part…

Génial !!! J’ai réussi…

Il manquait des dépendances de partout, j’ai du ajouter dans mon cronconfig.php des import des extensions, des components etc… ! Nickel.

[s]Bon, ma méthode run ne marche pas mais elle est assurément appelée !

[/s]

Merci pour votre aide (aux deux) j’ai pu résoudre tous mes problèmes !

[size="4"]AJOUT :[/size]

Si jamais votre save() échoue systématiquement, ajoutez dans votre config dans db :


'emulatePrepare' => false

Bonjour

Comme indiqué, j’utilise ‘yiic’ ce qui permet justement de s’appuyer sur ce qui a déjà été pensé dans le Framework.

Mon cron fait appel à des scripts shell qui eux appellent yiic. Histoire de pouvoir ajouter des traces qui sont eux suivi avec monit pour valider le bon fonctionnement.

Cela donne par exemple:


LOG_FILE=/var/log/project/customer.log

DEST_DIR=/home/ftpuser/customer

date >> $LOG_FILE

ENTITY_ID=5591

/usr/bin/php5 $PHP_EXTRAOPT -d max_execution_time=900 ${WEBROOT:=/var/www/project}/protected/yiic extractcustomer $ENTITY_ID $DEST_DIR  2>&1 >> $LOG_FILE



En ce qui concerne les modèles de base, j’en ai également. Je les inclus directement dans le fichier de la classe dérivée:


Yii::import('application.models._base.BaseUser');

Maintenant ce chemin est quand même plutôt absolu et différent du tiens. A vérifier s’il est correct dans ton cas par exemple.