RE: Doctrine integration - ScientiFist - 11-30-2019
Hello jasonzig,
Quote:Maybe it's better in an another thread ?
Documentation:
Doctrine: https://www.doctrine-project.org/projects/doctrine-orm/en/2.6/tutorials/getting-started.html#getting-started-with-doctrine
1) SERVER:
I'm using php 7.2.9, Nginx, MariaDb, phpmyadmin and composer.
2) CODEIGNITER:
I used composer to install codeigniter, you can find more information:
https://codeigniter4.github.io/userguide/installation/installing_composer.html
Code: composer create-project codeigniter4/appstarter project-root -s rc
=> You should have a welcome page on your browser
=> I'm always also putting CodeIgniter in dev mode (Up to You)
3) INSTALLATION OF DOCTRINE:
Composer to add doctrine:
=> composer.json (should be at the base of your project)
https://www.doctrine-project.org/projects/doctrine-orm/en/2.6/tutorials/getting-started.html#project-setup
You need to add:
Code: {
"require": {
"doctrine/orm": "^2.6.2",
"symfony/yaml": "2.*"
},
"autoload": {
"psr-0": {"": "src/"}
}
}
after in the console: 'composer install' and 'composer update'
4) CREATING THE DOCTRINE LIBRARIE: (FOR CI)
=>App/Libraries/Doctrine.php
PHP Code: <?php namespace App\Libraries;
//WE INCLUDING THE AUTOLOAD VENDOR include_once dirname(__DIR__, 2) . '/vendor/autoload.php';
use Doctrine\Common\ClassLoader; use Doctrine\ORM\EntityManager; use Doctrine\ORM\Tools\Setup; use Doctrine\ORM\Mapping\Driver\YamlDriver;
// TO OBTAIN THE ENTITY MANAGER class Doctrine {
public $em;
public function __construct() {
// CONNECTION SETUP YOU NEED TO CHANGE WITH YOURS DBB $connection_options = array( 'driver' => 'pdo_mysql', 'user' => 'root', 'password' => 'password', 'host' => 'localhost', 'dbname' => 'project', 'charset' => 'utf8', 'driverOptions' => array( 'charset' => 'utf8', ), );
// PATH OF YOUR MODELS HERE ITS : APP/Models/Entities $models_namespace = 'Entities'; $models_path = APPPATH . 'Models'; $proxies_dir = APPPATH . 'Models/Proxies'; $metadata_paths = array(APPPATH . 'Models/Entities');
// DEV_MODE TRUE TO DISABLE CACHE $dev_mode = true; $cache = null; $useSimpleAnnotationReader = false;
// METADATA CONFIGURATION: CHECK IN THE DOCUMENTATION IF YOU WANT TO USE XML OR YAML // createXMLMetadataConfiguration or createYAMLMetadataConfiguration $config = Setup::createAnnotationMetadataConfiguration($metadata_paths, $dev_mode, $proxies_dir, $cache, $useSimpleAnnotationReader); $this->em = EntityManager::create($connection_options, $config);
//YAML $yamlDriver = new YamlDriver(APPPATH . 'Models/Mappings'); $config->setMetadataDriverImpl($yamlDriver); $loader = new ClassLoader($models_namespace, $models_path); $loader->register(); }
}
5) CREATING THE FOLDERS:
You need to create in the Models folder the following folders:
'Entities' => Models/Entities
'Proxies' => Models/Proxies
'Mappings' => Models/Mappings => The one you will use to create your tables
6) CREATING THE COMMAND LINE DOCTRINE:
=> In your App folder
App/Doctrine.php
PHP Code: <?php //DEFINE ENV define('APPPATH', dirname(__FILE__) . '/'); define('ENVIRONMENT', 'development'); chdir(APPPATH);
//CALL THE ENTITY MANAGER require __DIR__ . '/Libraries/Doctrine.php';
//GET THE HELPERS foreach ($GLOBALS as $helperSetCandidate) { if ($helperSetCandidate instanceof \Symfony\Component\Console\Helper\HelperSet) { $helperSet = $helperSetCandidate; break; } }
//CALL THE ENTITY $doctrine = new App\Libraries\Doctrine; $em = $doctrine->em;
//MAKE THE CONNECTION $helperSet = new \Symfony\Component\Console\Helper\HelperSet(array( 'db' => new \Doctrine\DBAL\Tools\Console\Helper\ConnectionHelper($em->getConnection()), 'em' => new \Doctrine\ORM\Tools\Console\Helper\EntityManagerHelper($em) ));
\Doctrine\ORM\Tools\Console\ConsoleRunner::run($helperSet);
I'm also using a shortcut
=>App/doctrine
PHP Code: #!/usr/bin/env php <?php
include('Doctrine.php');
7) TEST THE COMMAND LINE:
If everything is well setup you should be able to call doctrine in your console:
By a simple 'php doctrine' (if you using the shortcut) or by a 'php Doctrine.php'
And you should get a :
Code: Doctrine Command Line Interface 2.6.4-DEV
ALL THE COMMANDS YOU CAN DO:
......
....
8) DOCTRINE AS A SERVICE:
Quote:Special thanks to: MGatner and InsiteFx
=> App/Config/Services.php
You need to edit your services.php to add doctrine as a serviceStill need some optimization i guess)
PHP Code: class Services extends CoreServices {
//DOCTRINE SERVICE CLASS public static function doctrine($getShared = false) { if (! $getShared) { // INITIATE $doctrine = new \App\Libraries\Doctrine; // SHORTCUT ENTITY MANAGER $em = $doctrine->em; // RETURN ENTITY MANAGER return $em; } return static::getSharedInstance('doctrine'); } }
9) TEST :
Now in your BaseController you can call this service and make a test:
PHP Code: public function index() { // CALLING THE SERVICE WAY 1 //$em = \Config\Services::doctrine(); // CALLING THE SERVICE WAY 2 $em = service('doctrine'); var_dump($em); return view('welcome_message'); }
It's should dump all the entity manager variables.
10) HOW TO USE IT:
Let's Create a test table:
A)Generate an entity:
In the folder 'Mappings' you can create a file called 'test' in yml:
=>app/Models/Mappings/Entities.Test.dcm.yml
Entities.Test.dcm.yml (Will be our 'test' table)
Code: Entities\Test:
type: entity
table: test
uniqueConstraints:
id_index:
columns:
- id_test
fields:
id_test:
type: integer
unique: true
id: true
generator:
strategy: AUTO
text:
type: text
B) Generate the class:
Code: php doctrine orm:generate-entities Models
C) Generate the proxies:
Code: php doctrine orm:generate-proxies
D) Create the table in our Dbb:
Code: php doctrine orm:schema-tool:create
php doctrine orm:schema-tool:update --force
Now you can just use doctrine in your controllers to get back information to update to insert etc:
Quote:Check the Doctrine documentation for more information
E) Get back the info:
PHP Code: public function index() { $em = service('doctrine');
// EXAMPLE 1: $test = $em->getRepository('Entities\Test')->findAll(); var_dump($test); return view('welcome_message'); }
If there is something not clear or if you see something to change just let me know
It's will be a pleasure to help you
Regards,
RE: Doctrine integration - MGatner - 12-01-2019
What a thorough write up! Thanks to ScientiFist for sharing. This does make me realize how involved Doctrine is. I’ve never used it, and it seems like it overlaps with quite a bit of framework code and function. Do you mind me asking why everyone wants it? What do you use Doctrine for?
RE: Doctrine integration - troturier - 12-06-2019
Hello! Thanks for your tutorial, it helped me a lot!
For my part, I used Entities present in CI modules (folder App\Modules) for the mapping. (I can provide some code snippets if you are interested)
Everything works without problems, however, I was wondering if it was possible to access Doctrine commands on a remote host (OVH for example) for shared servers (in SSH maybe)? Or if we could simply call the commands of Doctrine (update DB schema, ...) without terminal access?
Thanks again!
EDIT: I ended up figuring out how to do it if someone is interested:
PHP Code: <?php namespace DoctrineMod\Controllers;
use Doctrine\ORM\Tools\SchemaValidator; use Doctrine\ORM\Tools\ToolsException;
class C_Doctrine extends \CodeIgniter\Controller { /** * Updates DB schema */ public function updateSchema(){ $em = service('doctrine'); $tool = new \Doctrine\ORM\Tools\SchemaTool($em); $tool->updateSchema($this->getEntitiesMetadata()); }
/** * Creates DB schema */ public function createSchema(){ $em = service('doctrine'); $tool = new \Doctrine\ORM\Tools\SchemaTool($em); try { $tool->createSchema($this->getEntitiesMetadata()); } catch (ToolsException $e) { echo $e->getMessage(); } }
/** * Validates current schema and returns eventual errors */ public function validateSchema(){ $em = service('doctrine');
$validator = new SchemaValidator($em); try { $errors = $validator->validateMapping(); if (count($errors) > 0) { echo implode("\n\n", $errors); } } catch (\Exception $e) { echo $e->getMessage(); } }
/** * @return array Entities metadata */ public function getEntitiesMetadata(){ $em = service('doctrine');
$entities = array();
$modulePath = APPPATH."Modules"; foreach (scandir($modulePath) as $module){ if(is_dir($modulePath."/".$module."/Entities")){ foreach (scandir($modulePath."/".$module."/Entities") as $moduleName){ if ($moduleName != "." && $moduleName != "..") $entities[] = $em->getClassMetadata(str_replace(".php", "",$module."\Entities\\".$moduleName)); } } } return $entities; } }
Just call these functions to run Doctrine commands directly from a PHP page (without using a terminal).
As a reminder, my Entities are not in the CI4 basic Models\Entities folder. I use modules that have the following structure: app\Modules\{module_name}\Entities.
Here is my Libraries\Doctrine.php class:
PHP Code: <?php namespace App\Libraries;
use Doctrine\ORM\EntityManager; use Doctrine\ORM\Tools\Setup;
include_once dirname(__DIR__, 2) . '/vendor/autoload.php';
class Doctrine {
public $em = null;
public function __construct() { // Retrieving all paths leading to entities classes $modulePath = APPPATH."Modules\*\Entities"; $entitiesPath = glob($modulePath, GLOB_ONLYDIR);
/* * If `$isDevMode` is true caching is done in memory with the ArrayCache. Proxy objects are recreated on every request. * If `$isDevMode` is false, check for Caches in the order APC, Xcache, Memcache (127.0.0.1:11211), Redis (127.0.0.1:6379) unless `$cache` is passed as fourth argument. * If `$isDevMode` is false, set then proxy classes have to be explicitly created through the command line. * If third argument `$proxyDir` is not set, use the systems temporary directory. */ $isDevMode = false;
if (function_exists('db_connect')){ $db = db_connect(); }
// Generating DB connection configuration array $dbParams = array( 'driver' => "mysqli", 'user' => {REDACTED}, 'password' => {REDACTED}, 'dbname' => {REDACTED}, );
$proxies_dir = APPPATH . 'Models/Proxies';
$config = Setup::createAnnotationMetadataConfiguration($entitiesPath, $isDevMode, $proxies_dir);
try { $this->em = EntityManager::create($dbParams, $config); } catch (\Doctrine\ORM\ORMException $e) { log_message("Doctrine Exception : ", $e); } } }
So, I do not use a YAML file for mapping but annotations directly in my Entities.
Hope this can help someone else! Have a nice day!
RE: Doctrine integration - ScientiFist - 03-17-2020
@troturier Really a good idea to use the ci module i will take a look thank you !
|