doctrine
Symfony: Contrôle de la disponibilité de la base de données avec un event
31/01/10
Symfony, depuis la version 1.2, offre un système d’événements (sfEventDispatcher et sfEvent). Cela va permettre la mise en place de notre contrôle. Pour cela nous allons nous connecter à l’événement « doctrine.configure_connection ». Nous allons effectuer cela dans notre application configuration (frontend) avec le code ci-dessous:
class frontendConfiguration extends sfApplicationConfiguration
{
public function configure()
{
$this->dispatcher->connect('doctrine.configure_connection', array($this, 'listenToAddCheckDatabaseConnection'));
}
public function listenToAddCheckDatabaseConnection(sfEvent $event)
{
$actions = $event->getSubject();
$actions->getCurrentConnection()->connect();
sfConfig::set('sf_database_is_connected', $actions->getCurrentConnection()->isConnected());
}
}
Nous allons ensuite intercepter notre nouvelle configuration en personnalisant notre frontController. Pour cela, nous allons ajouter une nouvelle classe dans notre projet sous lib/controller/mySfFrontWebController.class.php
class mySfFrontWebController extends sfFrontWebController
{
public function dispatch()
{
if (!sfConfig::get('sf_database_is_connected', true))
{
$request = $this->context->getRequest();
$moduleName = $request->getParameter('module');
$actionName = $request->getParameter('action');
if ((!$module = sfConfig::get('app_database_not_connected_module')) ||
(!$action = sfConfig::get('app_database_not_connected_action')))
{
throw new sfConfigurationException('Missing parameter(s): app_database_not_connected_module and app_database_not_connected_action are required in app.yml');
}
else
{
if (($moduleName != $module) && ($actionName != $action))
{
$this->forward($module, $action);
exit;
}
}
}
parent::dispatch();
}
}
Pour charger notre nouvelle classe, nous allons le faire dans le fichier factories.yml de notre application (frontend):
all:
controller:
class: mySfFrontWebController
Nous allons définir nos nouveaux paramètres dans le fichier app.yml de notre application (frontend):
all:
database_not_connected:
module: main
action: notconnected
Il nous reste maintenant à définir notre nouvelle action dans le module main (ou autre).
Voilà. La mise en place du contrôle de connexion sur notre base de données est terminée.
J’espère que ce petit bout de code vous servira.
Symfony: Afficher un message en cas de non disponibilité de la base de données
13/12/09
Symfony ne proposant pas une fonctionnalité me permettant de définir un message en cas de non disponibilité de la base de données, j’ai réalisé un filtre pour contrôler cela. Pour le rendre flexible, j’ai ajouté deux options permettant la définition du module et de l’action appelé lors de l’erreur.
J’ai commencé par créer dans mon module default, une action checkAvailibility me permettant de réaliser un template pour l’affichage du message (je passe sur cette étape car je pense que vous savez le faire). Ensuite, il suffit de les définir dans le fichier app.yml:
all:
checkdb:
module: default
action: checkAvailibility
J’ai ensuite créé mon fichier filtre appelé « checkAvailibilityDbFilter.class.php » dans le dossier /lib de mon projet:
class checkAvailibilityDbFilter extends sfFilter
{
public function execute($filterChain)
{
if ($this->isFirstCall())
{
$context = $this->getContext();
$module = sfConfig::get('app_checkdb_module', 'default');
$action = sfConfig::get('app_checkdb_action', 'error404');
if (($module != $context->getModuleName()) || ($action != $context->getActionName()))
{
$configuration = sfProjectConfiguration::getActive();
$db = new sfDatabaseManager($configuration);
foreach ($db->getNames() as $connection)
{
try
{
@$db->getDatabase($connection)->getConnection();
}
catch(Exception $e)
{
$context->getController()->forward($module, $action);
exit;
}
}
}
}
$filterChain->execute();
}
}
Il reste encore à activer ce filtre pour que cela fonctionne. J’ai ajouté les lignes suivantes dans le fichier filters.yml du dossier config de l’application:
rendering: ~ security: ~ # insert your own filters here db: class: checkAvailibilityDbFilter cache: ~ common: ~ execution: ~
J’espère que cette petite astuce vous sera utile.
Le cache de résultat avec doctrine
19/03/09
Note préalable: Nous utilisons dans cette article le système de cache php APC. Vous devez installer celui-ci sur votre configuration pour que l’exemple ci-dessous fonctionne.
Doctrine a en standard la possibilité de mettre en cache les résultats d’une requête. Il propose entre autre Memcached, APC, Sqlite. Nous allons l’utiliser dans le cadre d’un exemple symfony.
Pour commencer, nous allons initialiser une variable contenant la durée de vie du cache dans le fichier app.yml de notre application:
all:
cache:
lifetime: 3600
Nous allons maintenant initialiser le cache APC de doctrine. Le code ci-dessous est à mettre dans la classe de configuration de votre application:
class frontendConfiguration extends sfApplicationConfiguration
{
public function configure()
{
}
public function configureDoctrine(Doctrine_Manager $manager)
{
/* Initialisation du cache Doctrine APC */
$cacheDriver = new Doctrine_Cache_Apc();
$manager->setAttribute(Doctrine::ATTR_QUERY_CACHE, $cacheDriver);
$manager->setAttribute(Doctrine::ATTR_QUERY_CACHE_LIFESPAN, sfConfig::get('app_cache_lifetime'));
$manager->setAttribute(Doctrine::ATTR_RESULT_CACHE, $cacheDriver);
$manager->setAttribute(Doctrine::ATTR_RESULT_CACHE_LIFESPAN, sfConfig::get('app_cache_lifetime'));
}
}
Pour cette exemple, j’utilise le modèle suivant:
---
dUser:
tableName: d_user
columns:
id:
type: integer(3)
primary: true
autoincrement: true
fullname:
type: string(160)
notnull: true
street:
type: string(160)
zip:
type: string(10)
city:
type: string(80)
country:
type: string(60)
Dans la classe du modèle ci-dessus, nous allons utiliser le cache. La directive useResultCache est ajouté à la requête.
class dUserTable extends Doctrine_Table
{
public function findFullnameOrderByAsc()
{
return $this->createQuery('u')
->select('u.fullname, u.city')
->orderBy('fullname')
->useQueryCache()
->useResultCache()
->execute();
}
}
Il vous suffit ensuite d’exécuter votre requête dans votre action avec le code suivant pour récupérer le résultat.
$this->users = Doctrine::getTable('dUser')->findFullnameOrderByAsc();
Si vous utilisez la debug toolbar, vous constaterez qu’à la première requête, vous aurez 1 appel à la base de donnée mais que si vous rechargez votre page html, aucune nouvelle requête n’est lancée. Le cache fonctionne.
J’espère que ce point de départ vous aidera dans vos découvertes. N’hésitez pas à poster vos découvertes dans les commentaires.
Merci à [MA]Pascal pour la piste de configuration.
Références:
- Documentation Doctrine sur le cache
- La documentation du cache PHP alternatif APC
- L’extension php apc
Article:
- Performance Tuning in PHP
Initialisation d’un projet symfony/doctrine sous subversion
19/03/09
La première phase consiste à créer notre dossier http. Mon path par défaut pour cette exemple est /www/virtualhosts. Les noms entre crochets sont utilisés pour un élément variable.
mkdir /www/virtualhosts/[projet]
Nous allons maintenant nous déplacer dans ce dossier et le déchargement de la base depuis subversion
cd /www/virtualhosts/[projet] svn co http://[svn.server]/repos/[project]/trunk .
Nous pouvons maintenant installer le framework symfony dans notre dossier http
/www/svn/symfony/1.2/data/bin/symfony generate:project [NomDuProjet]
Nous allons maintenant configurer la base de donnée avec doctrine:
./symfony configure:database --name=doctrine --class=sfDoctrineDatabase "mysql:host=localhost;dbname=database" user pass
Modification du fichier databases.yml:
cd config/ Suppression des lignes concernant Propel dans le fichier databases.yml (ne laisser que la config doctrine)
Nous renommons le fichier databases.yml avant de l’inclure dans le repository
mv databases.yml databases.yml_dist
Activation du plugin sfDoctrinePlugin
Ouvrir le fichier ProjectConfiguration.class.php et changer sfDoctrinePlugin par sfPropelPlugin
Suppression des fichiers inutiles
rm -fr propel.ini rm -fr schema.yml
Création du dossier doctrine qui va recevoir les fichiers schéma
mkdir doctrine
Suppression du dossier sfPropelPlugin du dossier web et activation du dossier sfDoctrinePlugin
cd ../web/ unlink sfPropelPlugin cd .. ./symfony plugin:publish-assets
Prochaine étape, vider les dossiers cache et log
rm -fr cache/* rm -fr log/*
Ajout de notre projet dans subversion
svn add *
Nous allons ignorer les fichiers des dossiers cache et log
svn pe svn:ignore cache > * svn pe svn:ignore log > *
Nous mettons également le fichier databases.yml en ignore pour ne pas tenir compte de la configuration locale
svn pe svn:ignore config > databases.yml
Création du dossier sql recevant les fichiers sql de doctrine. Je considère que ces fichiers ne sont pas à versionner. Nous allons également les ignorer.
mkdir data/sql svn pe svn:ignore data/sql > *
Nous allons inclure symfony dans notre projet
svn mkdir lib/vendor svn pe svn:externals lib/vendor > symfony http://svn.symfony-project.com/branches/1.2
Transfert de notre structure initiale sur le serveur subversion
svn ci -m 'Projet initial'
Nous allons maintenant lancer un update pour charger le framework symfony qui a été précédemment accroché dans le dossier lib/vendor
svn up
Nous allons changer le chemin d’accès aux librairies symfony en modifiant le fichier ProjectConfiguration.class.php du dossier config du projet
Changer: require_once '/www/svn/symfony/1.2/lib/autoload/sfCoreAutoload.class.php' Par: require_once dirname(__FILE__).'/../lib/vendor/symfony/lib/autoload/sfCoreAutoload.class.php';
Nous allons publié notre modification sur le serveur subversion
svn ci -m "Changement de la configuration"
Il nous reste une dernière chose à faire pour que notre projet fonctionne. Nous allons copier le fichier databases.yml_dist et le renommer avant de le modifier pour tenir compte de notre configuration locale
cp config/databases.yml_dist config/databases.yml
Il ne reste plus qu’à initialiser notre application avant de pouvoir développer
./symfony generate:app frontend --csrf-secret=CrSfS3Cr3t --escaping-strategy=on
Ajout de l’application à subversion
svn add test/functional/frontend apps/frontend web/frontend_dev.php web/index.php
Publication sur le serveur subversion
svn ci -m "Initialisation de l'application frontend"
J’espère que cette démarche vous permettra de simplifier l’installation de vos projets. Je reste à votre disposition si vous avez des questions sur le sujet.
Références:
- Le Framework Symfony
- l’ORM Doctrine
- Subversion
