Doctrine est également un ORM qui peut être associé à CodeIgniter, il est beaucoup plus puissant, et plus complet.
Doctrine est installé en tant que bibliothèque dans codeIgniter.
Créer un nouveau projet PHP, installer à nouveau CodeIgniter.
Avec l'archive Doctrine :
Créer une classe Doctrine.php dans le dossier libraries :
<?php class Doctrine { // the Doctrine entity manager public $em = null; public function __construct() { // include our CodeIgniter application's database configuration require APPPATH.'config/database.php'; // include Doctrine's fancy ClassLoader class require_once APPPATH.'libraries/Doctrine/Common/ClassLoader.php'; // load the Doctrine classes $doctrineClassLoader = new \Doctrine\Common\ClassLoader('Doctrine', APPPATH.'libraries'); $doctrineClassLoader->register(); // load Symfony2 helpers // Don't be alarmed, this is necessary for YAML mapping files $symfonyClassLoader = new \Doctrine\Common\ClassLoader('Symfony', APPPATH.'libraries/Doctrine'); $symfonyClassLoader->register(); // load the entities $entityClassLoader = new \Doctrine\Common\ClassLoader('Entities', APPPATH.'models'); $entityClassLoader->register(); // load the proxy entities $proxyClassLoader = new \Doctrine\Common\ClassLoader('Proxies', APPPATH.'models'); $proxyClassLoader->register(); // set up the configuration $config = new \Doctrine\ORM\Configuration; if(ENVIRONMENT == 'development') // set up simple array caching for development mode $cache = new \Doctrine\Common\Cache\ArrayCache; else // set up caching with APC for production mode $cache = new \Doctrine\Common\Cache\ApcCache; $config->setMetadataCacheImpl($cache); $config->setQueryCacheImpl($cache); // set up proxy configuration $config->setProxyDir(APPPATH.'models/Proxies'); $config->setProxyNamespace('Proxies'); // auto-generate proxy classes if we are in development mode $config->setAutoGenerateProxyClasses(ENVIRONMENT == 'development'); // set up annotation driver //$yamlDriver = new \Doctrine\ORM\Mapping\Driver\YamlDriver(APPPATH.'models/Mappings'); $driverImpl = $config->newDefaultAnnotationDriver(APPPATH.'models'); $config->setMetadataDriverImpl($driverImpl); // Database connection information $connectionOptions = array( 'driver' => 'pdo_mysql', 'user' => $db['default']['username'], 'password' => $db['default']['password'], 'host' => $db['default']['hostname'], 'dbname' => $db['default']['database'] ); // create the EntityManager $em = \Doctrine\ORM\EntityManager::create($connectionOptions, $config); // store it as a member, for use in our CodeIgniter controllers. $this->em = $em; } } ?>
Doctrine doit être ensuite chargé automatiquement avec autoload.php :
$autoload['libraries'] = array('database','doctrine');
Logiquement, Doctrine est prêt à fonctionner.
Vérifier que votre page d'accueil ne produit pas d'erreurs : http://localhost/siteURL/
Une classe métier correspond à la notion d'entity dans Doctrine.
Considérons la base de données suivante :
La base de données sera composée de 2 entities: utilisateur et categorie. La relation de type CIF entre utilisateurs et categories peut s'exprimer de la façon suivante :
Dans le dossier application/models :
<?php /** * @Entity * @Table(name="utilisateurs") */ class Utilisateur { /** * @Id @Column(type="integer") * @GeneratedValue */ private $id; /** * @Column(type="string") * @var string */ private $nom; /** * @Column(type="string") * @var string */ private $prenom; /** * @Column(type="integer") * @var integer */ private $age; /** * @Column(type="boolean") * @var string */ private $adulte; /** * @ManyToOne(targetEntity="Categorie") * @JoinColumn(name="categorie_id", referencedColumnName="id") */ private $categorie; } ?>
Dans le dossier application/models :
<?php /** * @Entity * @Table(name="categories") */ class Categorie{ /** * @Id @Column(type="integer") * @GeneratedValue */ private $id; /** * @Column(type="string") * @var string */ private $nom; /** * @OneToMany(targetEntity="Utilisateur",mappedBy="categorie") */ private $utilisateurs; } ?>
Le chargement peut être automatique, par le biais de application/config/autoload.php
$autoload['model'] = array('categorie','utilisateur');
ou bien se faire dans un contrôleur :
$this->load->model('utilisateur');
Ajouter un contrôleur utilisateurs dans controllers :
<?php class Utilisateurs extends CI_Controller{ public function all(){ $query = $this->doctrine->em->createQuery("SELECT u FROM Utilisateur u join u.categorie c"); $users = $query->getResult(); $this->load->view('v_utilisateurs',array('utilisateurs'=>$users)); } } ?>
Créer la vue v_utilisateurs pour afficher la liste des utilisateurs : La variable $utilisateurs est récupérée par la méthode all du contrôleur utilisateurs
<?php foreach ($utilisateurs as $user){ echo($user->getNom()." (".$user->getCategorie()->getNom().")<br>"); } ?>
Tester en allant à l'adresse /utilisateurs/all/
Modifier le contrôleur utilisateurs :
<?php class Utilisateurs extends CI_Controller{ public function add(){ $this->load->helper(array('form', 'url')); $this->load->library('form_validation'); $this->form_validation->set_rules('username', 'Username', 'trim|required|min_length[5]|max_length[12]|xss_clean'); if ($this->form_validation->run() == FALSE) { $this->load->view('v_utilisateur_add'); } else { $this->submit_add($_POST["username"]); } } public function submit_add($name){ $user = new Utilisateur(); $user->setNom($name); $this->doctrine->em->persist($user); $this->doctrine->em->flush(); } public function all(){ $query = $this->doctrine->em->createQuery("SELECT u FROM Utilisateur u join u.categorie c"); $users = $query->getResult(); $this->load->view('v_utilisateurs',array('utilisateurs'=>$users)); } } ?>
La vue v_utilisateur_add sera appelée par l'intermédiaire du contrôleur utilisateurs/add
<html> <head> <title>Ajout utilisateur</title> </head> <body> <?php echo validation_errors(); ?> <?php echo form_open('utilisateurs/add/'); ?> <h5>Nom d'utilisateur</h5> <input type="text" name="username" value="<?php echo set_value('username'); ?>" size="50" /> <div><input type="submit" value="Ajouter utilisateur" /></div> </form> </body> </html>
La vue v_success_add sera appelée après soumission du formulaire par le contrôleur utilisateurs/submit_add
<?php echo($user->nom." ajouté"); ?>
Tester en allant à l'adresse : http://localhost/testPhp/utilisateurs/add/
Vérifier l'insertion dans la base de données du nouvel utilisateur.
L'accès à la base de données doit-être correctement configuré dans le fichier config/database.php.
Doctrine est installé en tant que Librairie.
Créer le fichier doctrine-cli.php dans le dossier application, et modifier la variable APPPATH : partie siteURL
<?php
// trailing slash is important!
define('APPPATH', 'c:/xampp/htdocs/siteURL/application/');
define('BASEPATH', APPPATH);
define('ENVIRONMENT', 'production');
require APPPATH.'libraries/Doctrine.php';
$doctrine = new Doctrine();
$helperSet = new \Symfony\Component\Console\Helper\HelperSet(array(
'db' => new \Doctrine\DBAL\Tools\Console\Helper\ConnectionHelper($doctrine->em->getConnection()),
'em' => new \Doctrine\ORM\Tools\Console\Helper\EntityManagerHelper($doctrine->em)
));
$cli = new \Symfony\Component\Console\Application('Doctrine Command Line Interface (CodeIgniter integration by Joel Verhagen)', Doctrine\ORM\Version::VERSION);
$cli->setCatchExceptions(true);
$cli->setHelperSet($helperSet);
$cli->addCommands(array(
// DBAL Commands
new \Doctrine\DBAL\Tools\Console\Command\RunSqlCommand(),
new \Doctrine\DBAL\Tools\Console\Command\ImportCommand(),
// ORM Commands
new \Doctrine\ORM\Tools\Console\Command\ClearCache\MetadataCommand(),
new \Doctrine\ORM\Tools\Console\Command\ClearCache\ResultCommand(),
new \Doctrine\ORM\Tools\Console\Command\ClearCache\QueryCommand(),
new \Doctrine\ORM\Tools\Console\Command\SchemaTool\CreateCommand(),
new \Doctrine\ORM\Tools\Console\Command\SchemaTool\UpdateCommand(),
new \Doctrine\ORM\Tools\Console\Command\SchemaTool\DropCommand(),
new \Doctrine\ORM\Tools\Console\Command\EnsureProductionSettingsCommand(),
new \Doctrine\ORM\Tools\Console\Command\ConvertDoctrine1SchemaCommand(),
new \Doctrine\ORM\Tools\Console\Command\GenerateRepositoriesCommand(),
new \Doctrine\ORM\Tools\Console\Command\GenerateEntitiesCommand(),
new \Doctrine\ORM\Tools\Console\Command\GenerateProxiesCommand(),
new \Doctrine\ORM\Tools\Console\Command\ConvertMappingCommand(),
new \Doctrine\ORM\Tools\Console\Command\RunDqlCommand(),
new \Doctrine\ORM\Tools\Console\Command\ValidateSchemaCommand(),
));
$cli->run();
?>
Lancer la console, et redéfinir la variable PATH pour permettre l'accès au programme php en ligne de commande :
SET PATH=%PATH%;c:\xampp\php echo %PATH%
Aller dans le dossier application du site, et exécuter :
php doctrine-cli.php
La sortie écran devrait produire le résultat suivant :
Doctrine Command Line Interface (CodeIgniter integration by Joel Verhagen) version 2.0.5 Usage: [options] command [arguments] Options: --help -h Display this help message. --quiet -q Do not output any message. --verbose -v Increase verbosity of messages. --version -V Display this program version. --ansi -a Force ANSI output. --no-interaction -n Do not ask any interactive question. Available commands: help Displays help for a command (?) list Lists commands dbal :import Import SQL file(s) directly to Database. :run-sql Executes arbitrary SQL directly from the command line. orm :convert-d1-schema Converts Doctrine 1.X schema into a Doctrine 2.X schema. :convert-mapping Convert mapping information between supported formats. :ensure-production-settings Verify that Doctrine is properly configured for a production environment. :generate-entities Generate entity classes and method stubs from your mapping information. :generate-proxies Generates proxy classes for entity classes. :generate-repositories Generate repository classes from your mapping information. :run-dql Executes arbitrary DQL directly from the command line. :validate-schema Validate that the mapping files. orm:clear-cache :metadata Clear all metadata cache of the various cache drivers. :query Clear all query cache of the various cache drivers. :result Clear result cache of the various cache drivers. orm:schema-tool :create Processes the schema and either create it directly on EntityManager Storage Connection or generate the SQL output. :drop Drop the complete database schema of EntityManager Storage Connection or generate the corresponding SQL output. :update Processes the schema and either update the database schema of EntityManager Storage Connection or generate the SQL output.
Nous allons générer les metadonnées de mapping à partir de la base de données existante, au format YAML :
<?php
class Doctrine
{
// the Doctrine entity manager
public $em = null;
public function __construct()
{
// include our CodeIgniter application's database configuration
require APPPATH.'config/database.php';
// include Doctrine's fancy ClassLoader class
require_once APPPATH.'libraries/Doctrine/Common/ClassLoader.php';
// load the Doctrine classes
$doctrineClassLoader = new \Doctrine\Common\ClassLoader('Doctrine', APPPATH.'libraries');
$doctrineClassLoader->register();
// load Symfony2 helpers
// Don't be alarmed, this is necessary for YAML mapping files
$symfonyClassLoader = new \Doctrine\Common\ClassLoader('Symfony', APPPATH.'libraries/Doctrine');
$symfonyClassLoader->register();
// load the entities
$entityClassLoader = new \Doctrine\Common\ClassLoader('Entities', APPPATH.'models');
$entityClassLoader->register();
// load the proxy entities
$proxyClassLoader = new \Doctrine\Common\ClassLoader('Proxies', APPPATH.'models');
$proxyClassLoader->register();
// set up the configuration
$config = new \Doctrine\ORM\Configuration;
if(ENVIRONMENT == 'development')
// set up simple array caching for development mode
$cache = new \Doctrine\Common\Cache\ArrayCache;
else
// set up caching with APC for production mode
$cache = new \Doctrine\Common\Cache\ApcCache;
$config->setMetadataCacheImpl($cache);
$config->setQueryCacheImpl($cache);
// set up proxy configuration
$config->setProxyDir(APPPATH.'models/Proxies');
$config->setProxyNamespace('Proxies');
// auto-generate proxy classes if we are in development mode
$config->setAutoGenerateProxyClasses(ENVIRONMENT == 'development');
// set up annotation driver
$yamlDriver = new \Doctrine\ORM\Mapping\Driver\YamlDriver(APPPATH.'models/Mappings');
$config->setMetadataDriverImpl($yamlDriver);
//$driverImpl = $config->newDefaultAnnotationDriver(APPPATH.'models');
//$config->setMetadataDriverImpl($driverImpl);
// Database connection information
$connectionOptions = array(
'driver' => 'pdo_mysql',
'user' => $db['default']['username'],
'password' => $db['default']['password'],
'host' => $db['default']['hostname'],
'dbname' => $db['default']['database']
);
// create the EntityManager
$em = \Doctrine\ORM\EntityManager::create($connectionOptions, $config);
// store it as a member, for use in our CodeIgniter controllers.
$this->em = $em;
}
}
?>
php doctrine-cli.php orm:convert-mapping --from-database yml models/Mappings
Processing entity "Categories" Processing entity "Droit" Processing entity "Projet" Processing entity "Utilisateurs" Exporting "yml" mapping information to "C:\xampp\htdocs\doctrine_CI\application\ models\Mappings"
Les fichier yml associés à chaque table de la BDD doivent être présents dans le dossier application/models/Mappings :
Utilisateurs:
type: entity
table: utilisateurs
fields:
id:
id: true
type: integer
unsigned: false
nullable: false
generator:
strategy: IDENTITY
prenom:
type: string
length: 50
fixed: false
nullable: true
dateinscription:
type: date
nullable: true
column: dateInscription
age:
type: integer
unsigned: false
nullable: true
nom:
type: string
length: 50
fixed: false
nullable: true
adulte:
type: boolean
nullable: false
manyToMany:
iddroit:
targetEntity: Droit
cascade: { }
mappedBy: null
inversedBy: idutilisateur
joinTable:
name: utilisateur_droit
joinColumns:
-
name: idUtilisateur
referencedColumnName: id
inverseJoinColumns:
-
name: idDroit
referencedColumnName: id
orderBy: null
oneToOne:
categorie:
targetEntity: Categories
cascade: { }
mappedBy: null
inversedBy: null
joinColumns:
categorie_id:
referencedColumnName: id
orphanRemoval: false
lifecycleCallbacks: { }
php doctrine-cli.php orm:convert-mapping --from-database xml models/Mappings
Nous allons maintenant générer les classes à partir des données de mapping : Avant la génération, vérifier les données, et procédez à d'éventuelles corrections.
php doctrine-cli.php orm:generate-entities --generate-annotations=true modelsL'exécution devrait retourner un résultat semblable à celui-ci :
Processing entity "Categories" Processing entity "Droit" Processing entity "Projet" Processing entity "Utilisateurs" Entity classes generated to "C:\xampp\htdocs\doctrine_CI\application\models"
Les classes sont générées dans application/models :
<?php
use Doctrine\ORM\Mapping as ORM;
/**
* Utilisateurs
*/
class Utilisateurs
{
/**
* @var integer $id
*/
private $id;
/**
* @var string $prenom
*/
private $prenom;
/**
* @var date $dateinscription
*/
private $dateinscription;
/**
* @var integer $age
*/
private $age;
/**
* @var string $nom
*/
private $nom;
/**
* @var boolean $adulte
*/
private $adulte;
/**
* @var Categories
*/
private $categorie;
/**
* @var \Doctrine\Common\Collections\ArrayCollection
*/
private $iddroit;
public function __construct()
{
$this->iddroit = new \Doctrine\Common\Collections\ArrayCollection();
}
/**
* Get id
*
* @return integer
*/
public function getId()
{
return $this->id;
}
/**
* Set prenom
*
* @param string $prenom
* @return Utilisateurs
*/
public function setPrenom($prenom)
{
$this->prenom = $prenom;
return $this;
}
/**
* Get prenom
*
* @return string
*/
public function getPrenom()
{
return $this->prenom;
}
/**
* Set dateinscription
*
* @param date $dateinscription
* @return Utilisateurs
*/
public function setDateinscription($dateinscription)
{
$this->dateinscription = $dateinscription;
return $this;
}
/**
* Get dateinscription
*
* @return date
*/
public function getDateinscription()
{
return $this->dateinscription;
}
/**
* Set age
*
* @param integer $age
* @return Utilisateurs
*/
public function setAge($age)
{
$this->age = $age;
return $this;
}
/**
* Get age
*
* @return integer
*/
public function getAge()
{
return $this->age;
}
/**
* Set nom
*
* @param string $nom
* @return Utilisateurs
*/
public function setNom($nom)
{
$this->nom = $nom;
return $this;
}
/**
* Get nom
*
* @return string
*/
public function getNom()
{
return $this->nom;
}
/**
* Set adulte
*
* @param boolean $adulte
* @return Utilisateurs
*/
public function setAdulte($adulte)
{
$this->adulte = $adulte;
return $this;
}
/**
* Get adulte
*
* @return boolean
*/
public function getAdulte()
{
return $this->adulte;
}
/**
* Set categorie
*
* @param Categories $categorie
* @return Utilisateurs
*/
public function setCategorie(\Categories $categorie = null)
{
$this->categorie = $categorie;
return $this;
}
/**
* Get categorie
*
* @return Categories
*/
public function getCategorie()
{
return $this->categorie;
}
/**
* Add iddroit
*
* @param Droit $iddroit
* @return Utilisateurs
*/
public function addDroit(\Droit $iddroit)
{
$this->iddroit[] = $iddroit;
return $this;
}
/**
* Get iddroit
*
* @return Doctrine\Common\Collections\Collection
*/
public function getIddroit()
{
return $this->iddroit;
}
}
$driverImpl = $config->newDefaultAnnotationDriver(APPPATH.'models'); $config->setMetadataDriverImpl($driverImpl);
Pour permettre la sérialisation d'instances de models en session, il est nécessaire de respecter certaines étapes :
Sur-définir éventuellement la méthode magique _sleep des classes, pour définir les membres à sérialiser :
public function __sleep(){
return array('id','login','password','nom','prenom','mail','monde','groupe');
}
S'il faut également prévoir la sérialisation des objets dépendants, préciser CASCADE=“ALL” et FETCH=“EAGER” sur les annotations concernées :
Exemple : sérialisation du groupe de l'utilisateur :
/**
* @var \Groupe
*
* @ManyToOne(targetEntity="Groupe",cascade={"all"}, fetch="EAGER")
* @JoinColumns({
* @JoinColumn(name="groupe_id", referencedColumnName="id")
* })
*/
private $groupe;
Utilisation de detach :
public function save(){
$user=DAO\getOne("Utilisateur", 1);
$this->doctrine->em->detach($user);
$this->session->set_userdata("user",$user);
echo $user->getNom()." enregistré";
}
Utilisation de merge :
public function load(){
var_dump($this->session->all_userdata());
$user=$this->session->userdata("user");
$user=$this->doctrine->em->merge($user);
var_dump($user);
}