Welcome Guest, Not a member yet? Register   Sign In
Doctrine integration
#11

(This post was last modified: 11-30-2019, 08:58 AM by ScientiFist.)

Hello jasonzig,

Quote:Maybe it's better in an another thread ? 

Documentation:
Doctrine: https://www.doctrine-project.org/project...h-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...poser.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/project...ject-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'
PHP Code:
php doctrine 

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 serviceSadStill 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 Smile

Regards,
Reply
#12

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?
Reply
#13

(This post was last modified: 12-06-2019, 08:33 AM by troturier.)

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  Big Grin  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($modulePathGLOB_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!  Big Grin
Reply
#14

@troturier Really a good idea to use the ci module i will take a look thank you !
Reply




Theme © iAndrew 2016 - Forum software by © MyBB