Monday, 15 October 2012

Configuring Doctrine ORM with PHP

I needed to configure Doctrine ORM with php. Tried first with CI framework some nights , but it felt like pain in the ass. In the end I started up configuring Doctrine ,Gedmo behavioral Extension with core php.

[STEP 1] Download Doctrine from github
After downloading doctrine orm, i put it under TGCore/app/thirdparty package.
(TGCore is the root folder of my app.)

[STEP 2] Creating Model /app/models/Country.php

<?php
namespace models;

use Doctrine\ORM\Mapping as ORM;
use Gedmo\Mapping\Annotation as Gedmo;
/**
 * @ORM\Entity(repositoryClass="models\repository\CountryRepository")
 * @ORM\Table(name="Country")
 *
 */
class Country{
/**
* @ORM\Id
* @ORM\Column(type="integer")
* @ORM\GeneratedValue
*/
public $id;

/**
* @ORM\Column(type="string", length=255, nullable=false)
*/
public $name;

/**
* @ORM\Column(type="string", length=255)
*/
public $description;

/**
* @var datetime $created
*
* @Gedmo\Timestampable(on="create")
* @ORM\Column(type="datetime")
*/
public $created;

/**
* @ORM\OneToMany(targetEntity="models\City",mappedBy="country")
*/
public $cities;

/**
* @ORM\Column(type="boolean")
*/
public $active;

public function __construct(){
    $this->id_type = new ArrayCollection();
    }
}



[STEP 3] Configuring Doctrine - /app/config/config.php


<?php
use Doctrine\Common\ClassLoader,
Doctrine\ORM\Configuration,
Doctrine\ORM\EntityManager,
Doctrine\Common\Cache\ArrayCache,
Doctrine\Common\Annotations\AnnotationReader,
Doctrine\ORM\Mapping\Driver\AnnotationDriver,
Doctrine\DBAL\Logging\EchoSqlLogger,
Doctrine\DBAL\Event\Listeners\MysqlSessionInit,
Doctrine\ORM\Tools\SchemaTool,
Doctrine\ORM\Tools\Setup,
Doctrine\Common\EventManager,
Gedmo\Timestampable\TimestampableListener,
Gedmo\Sluggable\SluggableListener,
Gedmo\Tree\TreeListener,
Gedmo\SoftDeleteable\SoftDeleteableListener,
Gedmo\Loggable\LoggableListener;

include_once(dirname(__FILE__) . '/database.php');
include_once 'app/thirdparty/Doctrine/Common/ClassLoader.php';
include_once 'app/thirdparty/Doctrine/ORM/Tools/Setup.php';

$APP_NAME = "TG";
if($_SERVER['HTTP_HOST'] == "localhost"){
$_CONFIG['base_url'] = "http://localhost/{$APP_NAME}/";
   $_CONFIG['base_path'] = $_SERVER['DOCUMENT_ROOT'] . "/{$APP_NAME}/";
}else{
$_CONFIG['base_url'] = "http://localhost/{$APP_NAME}/";
   $_CONFIG['base_path'] = $_SERVER['DOCUMENT_ROOT'] . "/{$APP_NAME}/";
}

define('ROOT_HOST', $_CONFIG['base_url']);
define('ROOT_DIR', $_CONFIG['base_path']);

/*********** Define the values *********/
define("HOSTNAME", $db['hostname']);
define("USERNAME", $db['username']);
define("PASSWORD", $db['password']);
define("DATABASE", $db['database']);
define("BASE_URL", ROOT_HOST);


$application_folder = 'app';
define('APPPATH', ROOT_DIR.$application_folder.'/');

define('EXT', '.php');

/**
 *
 * @var Doctrine\ORM\EntityManager
 */
$em = null;

/*bootstrapping doctrine*/
// Set up class loading
$doctrineClassLoader = new ClassLoader('Doctrine',  APPPATH.'thirdparty');
$doctrineClassLoader->register();

// Setting up Gedmo
$classLoader = new ClassLoader('Gedmo', APPPATH.'thirdparty');
$classLoader->register();

// Setting up custom extensions
$zExtensionsLoader = new ClassLoader('zamoon', APPPATH.'thirdparty');
$zExtensionsLoader->register();

// Setting up models loading
$entitiesClassLoader = new ClassLoader('models', APPPATH);
$entitiesClassLoader->register();

$proxiesClassLoader = new ClassLoader('Proxies', APPPATH.'models/proxies');
$proxiesClassLoader->register();

//print ("ensure standard doctrine annotations are registered<br/>");
Doctrine\Common\Annotations\AnnotationRegistry::registerFile(APPPATH.'thirdparty/Doctrine/ORM/Mapping/Driver/DoctrineAnnotations.php');

// print("Set up caches<br/>");
$ormConfig = new Doctrine\ORM\Configuration;
$arratyCache = new Doctrine\Common\Cache\ArrayCache;

$ormConfig->setMetadataCacheImpl($arratyCache);
$driverImpl = $ormConfig->newDefaultAnnotationDriver(array(APPPATH.'models/'));
$ormConfig->setMetadataDriverImpl($driverImpl);
$ormConfig->setQueryCacheImpl($arratyCache);

$ormConfig->setQueryCacheImpl($arratyCache);

// print("ORM Proxy configuration");
$ormConfig->setProxyDir(APPPATH.'/models/proxies');
$ormConfig->setProxyNamespace('Proxies');
$ormConfig->setAutoGenerateProxyClasses(TRUE); // this can be based on production config.

$evm = new Doctrine\Common\EventManager();

//print("gedmo extension listeners");
// sluggable
$sluggableListener = new Gedmo\Sluggable\SluggableListener;
// you should set the used annotation reader to listener, to avoid creating new one for mapping drivers
$sluggableListener->setAnnotationReader($cachedAnnotationReader);
$evm->addEventSubscriber($sluggableListener);

//loggable
$loggableListener = new Gedmo\Loggable\LoggableListener;
$loggableListener->setAnnotationReader($cachedAnnotationReader);
$evm->addEventSubscriber($loggableListener);


// timestampable
$timestampableListener = new Gedmo\Timestampable\TimestampableListener;
$timestampableListener->setAnnotationReader($cachedAnnotationReader);
$evm->addEventSubscriber($timestampableListener);


//soft delete
$softdeletelistener = new Gedmo\SoftDeleteable\SoftDeleteableListener;
$softdeletelistener->setAnnotationReader($cachedAnnotationReader);
$evm->addEventSubscriber($softdeletelistener);

//setup soft delete filter
$ormConfig->addFilter('soft-deleteable', 'Gedmo\SoftDeleteable\Filter\SoftDeleteableFilter');

// Database connection information
$connectionOptions = array(
        'driver' => 'pdo_mysql',
        'user' =>     "root",
        'password' => "mysql",
        'host' =>     "localhost",
        'dbname' =>   "TG"
);
//central access point to ORM functionality.
$em = EntityManager::create($connectionOptions, $ormConfig, $evm);
//create/drop/update database schemas based on  <tt>ClassMetadata</tt> class descriptors.
$tool = new SchemaTool($em);
if($em){
//ORM metadata descriptor for a class.
$schemas = array(
                                                $em->getClassMetadata('models\Country')
                                             );

}
//Create the databaseschema for the given array of ClassMetadata instances.
$tool->createSchema($this->schemas);
/* End of file config.php */
/* Location: ./app/config/config.php */


ERROR
Fatal error: Uncaught exception 'Doctrine\ORM\Mapping\MappingException' with message 'Class models\Country is not a valid entity or mapped super class.' in /var/www/TGCore/app/thirdparty/Doctrine/ORM/Mapping/MappingException.php:147
Stack trace:
#0 /var/www/TGCore/app/thirdparty/Doctrine/ORM/Mapping/Driver/AnnotationDriver.php(165): Doctrine\ORM\Mapping\MappingException::classIsNotAValidEntityOrMappedSuperClass('models\Country')
#1 /var/www/TGCore/app/thirdparty/Doctrine/ORM/Mapping/ClassMetadataFactory.php(293): Doctrine\ORM\Mapping\Driver\AnnotationDriver->loadMetadataForClass('models\Country', Object(Doctrine\ORM\Mapping\ClassMetadata))
#2 /var/www/TGCore/app/thirdparty/Doctrine/ORM/Mapping/ClassMetadataFactory.php(178): Doctrine\ORM\Mapping\ClassMetadataFactory->loadMetadata('models\Country')
#3 /var/www/TGCore/app/thirdparty/Doctrine/ORM/EntityManager.php(269): Doctrine\ORM\Mapping\ClassMetadataFactory->getMetadataFor('models\Country')
#4 /var/www/TGCore/app/config/deve in /var/www/TGCore/app/thirdparty/Doctrine/ORM/Mapping/MappingException.php on line 147








HACK

1 - Debugging Doctrine/ORM/EntityManager.php#getClassMetadata($className)
   /**
     * Returns the ORM metadata descriptor for a class.
     *
     * The class name must be the fully-qualified class name without a leading backslash
     * (as it is returned by get_class($obj)) or an aliased class name.
     *
     * Examples:
     * TGCore\app\models\Country
     * sales:PriceRequest
     *
     * @return \Doctrine\ORM\Mapping\ClassMetadata
     * @internal Performance-sensitive method.
     */
    public function getClassMetadata($className){
        return $this->metadataFactory->getMetadataFor($className);
    }


2 - Debugging Doctrine/ORM/Mapping/ClassMetadataFactory.php#getMetadataFor($className) - not available in Doctrine2 (I guess)


/**
     * Gets the class metadata descriptor for a class.
     *
     * @param string $className The name of the class.
     * @return \Doctrine\ORM\Mapping\ClassMetadata
     */
    public function getMetadataFor($className){
        if ( ! isset($this->loadedMetadata[$className])) {
            $realClassName = $className;

            // Check for namespace alias
            if (strpos($className, ':') !== false) {
                list($namespaceAlias, $simpleClassName) = explode(':', $className);
                $realClassName = $this->em->getConfiguration()->getEntityNamespace($namespaceAlias) . '\\' . $simpleClassName;

                if (isset($this->loadedMetadata[$realClassName])) {
                    // We do not have the alias name in the map, include it
                    $this->loadedMetadata[$className] = $this->loadedMetadata[$realClassName];

                    return $this->loadedMetadata[$realClassName];
                }
            }

            if ($this->cacheDriver) {
                if (($cached = $this->cacheDriver->fetch("$realClassName\$CLASSMETADATA")) !== false) {
                    $this->wakeupReflection($cached, $this->getReflectionService());
                    $this->loadedMetadata[$realClassName] = $cached;
                } else {
                    foreach ($this->loadMetadata($realClassName) as $loadedClassName) {
                        $this->cacheDriver->save(
                            "$loadedClassName\$CLASSMETADATA", $this->loadedMetadata[$loadedClassName], null
                        );
                    }
                }
            } else {
                $this->loadMetadata($realClassName);
            }

            if ($className != $realClassName) {
                // We do not have the alias name in the map, include it
                $this->loadedMetadata[$className] = $this->loadedMetadata[$realClassName];
            }
        }

        return $this->loadedMetadata[$className];
    }

3 - Doctrine/ORM/Mapping/ClassMetadataFactory.php#loadMetaData($realClassName)

    /**
     * Loads the metadata of the class in question and all it's ancestors whose metadata
     * is still not loaded.
     *
     * @param string $name The name of the class for which the metadata should get loaded.
     * @param array  $tables The metadata collection to which the loaded metadata is added.
     */
    protected function loadMetadata($name){
        if ( ! $this->initialized) {
            $this->initialize();
        }

        $loaded = array();

        $parentClasses = $this->getParentClasses($name);
        $parentClasses[] = $name;

        // Move down the hierarchy of parent classes, starting from the topmost class
        $parent = null;
        $rootEntityFound = false;
        $visited = array();
        foreach ($parentClasses as $className) {
            if (isset($this->loadedMetadata[$className])) {
                $parent = $this->loadedMetadata[$className];
                if ( ! $parent->isMappedSuperclass) {
                    $rootEntityFound = true;
                    array_unshift($visited, $className);
                }
                continue;
            }

            $class = $this->newClassMetadataInstance($className);
            $this->initializeReflection($class, $this->getReflectionService());

            if ($parent) {
                $class->setInheritanceType($parent->inheritanceType);
                $class->setDiscriminatorColumn($parent->discriminatorColumn);
                $class->setIdGeneratorType($parent->generatorType);
                $this->addInheritedFields($class, $parent);
                $this->addInheritedRelations($class, $parent);
                $class->setIdentifier($parent->identifier);
                $class->setVersioned($parent->isVersioned);
                $class->setVersionField($parent->versionField);
                $class->setDiscriminatorMap($parent->discriminatorMap);
                $class->setLifecycleCallbacks($parent->lifecycleCallbacks);
                $class->setChangeTrackingPolicy($parent->changeTrackingPolicy);
                if ($parent->isMappedSuperclass) {
                    $class->setCustomRepositoryClass($parent->customRepositoryClassName);
                }
            }

            // Invoke driver
            try {
                $this->driver->loadMetadataForClass($className, $class);
                //In my case, $class = Doctrine\ORM\Mapping\ClassMetadataInfo@00000000222ef1a300000000bfc98980
            } catch (ReflectionException $e) {
                throw MappingException::reflectionFailure($className, $e);
            }

            // If this class has a parent the id generator strategy is inherited.
            // However this is only true if the hierachy of parents contains the root entity,
            // if it consinsts of mapped superclasses these don't necessarily include the id field.
            if ($parent && $rootEntityFound) {
                if ($parent->isIdGeneratorSequence()) {
                    $class->setSequenceGeneratorDefinition($parent->sequenceGeneratorDefinition);
                } else if ($parent->isIdGeneratorTable()) {
                    $class->getTableGeneratorDefinition($parent->tableGeneratorDefinition);
                }
                if ($parent->generatorType) {
                    $class->setIdGeneratorType($parent->generatorType);
                }
                if ($parent->idGenerator) {
                    $class->setIdGenerator($parent->idGenerator);
                }
            } else {
                $this->completeIdGeneratorMapping($class);
            }

            if ($parent && $parent->isInheritanceTypeSingleTable()) {
                $class->setPrimaryTable($parent->table);
            }

            if ($parent && $parent->containsForeignIdentifier) {
                $class->containsForeignIdentifier = true;
            }

            if ($parent && !empty ($parent->namedQueries)) {
                $this->addInheritedNamedQueries($class, $parent);
            }

            $class->setParentClasses($visited);

            if ($this->evm->hasListeners(Events::loadClassMetadata)) {
                $eventArgs = new \Doctrine\ORM\Event\LoadClassMetadataEventArgs($class, $this->em);
                $this->evm->dispatchEvent(Events::loadClassMetadata, $eventArgs);
            }
            $this->wakeupReflection($class, $this->getReflectionService());

            $this->validateRuntimeMetadata($class, $parent);

            $this->loadedMetadata[$className] = $class;

            $parent = $class;

            if ( ! $class->isMappedSuperclass) {
                $rootEntityFound = true;
                array_unshift($visited, $className);
            }

            $loaded[] = $className;
        }

        return $loaded;
    }


4 - Doctrine/ORM/Mapping/Driver/AnnotationDriver.php#loadMetadataForClass($className, ClassMetadataInfo $metadata)

/**
     * {@inheritdoc}
     */
    public function loadMetadataForClass($className, ClassMetadataInfo $metadata)
{
        $class = $metadata->getReflectionClass();
        /* it results as follows for me
           /**
             * @ORM\Entity(repositoryClass="models\repository\CountryRepository")
             * @ORM\Table(name="Country")
             *
             */
             Class [  class models\Country ] {
                  @@ /var/www/TGCore/app/models/Country.php 10-46

                      - Constants [0] {}

                      - Static properties [0] {}

                      - Static methods [0] {}

                      - Properties [6] {
                        Property [  private $id ]
                        Property [  private $name ]
                        Property [  private $description ]
                        Property [  private $created ]
                        Property [  private $cities ]
                        Property [  private $active ]
          }
       */
        if (!$class) {
            // this happens when running annotation driver in combination with
            // static reflection services. This is not the nicest fix
            $class = new \ReflectionClass($metadata->name);
        }
        //problem is with _reader (AnnotationReader) i guess
        $classAnnotations = $this->_reader->getClassAnnotations($class);
        //in my case returning Array ( )
        if ($classAnnotations && is_numeric(key($classAnnotations))) {
            foreach ($classAnnotations as $annot) {
                $classAnnotations[get_class($annot)] = $annot;
            }
        }

        // Evaluate Entity annotation
        //this is where my code goes wrong 
        if (isset($classAnnotations['Doctrine\ORM\Mapping\Entity'])) {
            $entityAnnot = $classAnnotations['Doctrine\ORM\Mapping\Entity'];
            if ($entityAnnot->repositoryClass !== null) {
                $metadata->setCustomRepositoryClass($entityAnnot->repositoryClass);
            }
            if ($entityAnnot->readOnly) {
                $metadata->markReadOnly();
            }
        } else if (isset($classAnnotations['Doctrine\ORM\Mapping\MappedSuperclass'])) {
            $mappedSuperclassAnnot = $classAnnotations['Doctrine\ORM\Mapping\MappedSuperclass'];
            $metadata->setCustomRepositoryClass($mappedSuperclassAnnot->repositoryClass);
            $metadata->isMappedSuperclass = true;
        } else {
            throw MappingException::classIsNotAValidEntityOrMappedSuperClass($className);
        }

        // Evaluate Table annotation
        if (isset($classAnnotations['Doctrine\ORM\Mapping\Table'])) {
            $tableAnnot = $classAnnotations['Doctrine\ORM\Mapping\Table'];
            $primaryTable = array(
                'name' => $tableAnnot->name,
                'schema' => $tableAnnot->schema
            );

            if ($tableAnnot->indexes !== null) {
                foreach ($tableAnnot->indexes as $indexAnnot) {
                    $index = array('columns' => $indexAnnot->columns);

                    if ( ! empty($indexAnnot->name)) {
                        $primaryTable['indexes'][$indexAnnot->name] = $index;
                    } else {
                        $primaryTable['indexes'][] = $index;
                    }
                }
            }

            if ($tableAnnot->uniqueConstraints !== null) {
                foreach ($tableAnnot->uniqueConstraints as $uniqueConstraintAnnot) {
                    $uniqueConstraint = array('columns' => $uniqueConstraintAnnot->columns);

                    if ( ! empty($uniqueConstraintAnnot->name)) {
                        $primaryTable['uniqueConstraints'][$uniqueConstraintAnnot->name] = $uniqueConstraint;
                    } else {
                        $primaryTable['uniqueConstraints'][] = $uniqueConstraint;
                    }
                }
            }

            $metadata->setPrimaryTable($primaryTable);
        }

        // Evaluate NamedQueries annotation
        if (isset($classAnnotations['Doctrine\ORM\Mapping\NamedQueries'])) {
            $namedQueriesAnnot = $classAnnotations['Doctrine\ORM\Mapping\NamedQueries'];

            if (!is_array($namedQueriesAnnot->value)) {
                throw new \UnexpectedValueException("@NamedQueries should contain an array of @NamedQuery annotations.");
            }

            foreach ($namedQueriesAnnot->value as $namedQuery) {
                if (!($namedQuery instanceof \Doctrine\ORM\Mapping\NamedQuery)) {
                    throw new \UnexpectedValueException("@NamedQueries should contain an array of @NamedQuery annotations.");
                }
                $metadata->addNamedQuery(array(
                    'name'  => $namedQuery->name,
                    'query' => $namedQuery->query
                ));
            }
        }

        // Evaluate InheritanceType annotation
        if (isset($classAnnotations['Doctrine\ORM\Mapping\InheritanceType'])) {
            $inheritanceTypeAnnot = $classAnnotations['Doctrine\ORM\Mapping\InheritanceType'];
            $metadata->setInheritanceType(constant('Doctrine\ORM\Mapping\ClassMetadata::INHERITANCE_TYPE_' . $inheritanceTypeAnnot->value));

            if ($metadata->inheritanceType != \Doctrine\ORM\Mapping\ClassMetadata::INHERITANCE_TYPE_NONE) {
                // Evaluate DiscriminatorColumn annotation
                if (isset($classAnnotations['Doctrine\ORM\Mapping\DiscriminatorColumn'])) {
                    $discrColumnAnnot = $classAnnotations['Doctrine\ORM\Mapping\DiscriminatorColumn'];
                    $metadata->setDiscriminatorColumn(array(
                        'name' => $discrColumnAnnot->name,
                        'type' => $discrColumnAnnot->type,
                        'length' => $discrColumnAnnot->length
                    ));
                } else {
                    $metadata->setDiscriminatorColumn(array('name' => 'dtype', 'type' => 'string', 'length' => 255));
                }

                // Evaluate DiscriminatorMap annotation
                if (isset($classAnnotations['Doctrine\ORM\Mapping\DiscriminatorMap'])) {
                    $discrMapAnnot = $classAnnotations['Doctrine\ORM\Mapping\DiscriminatorMap'];
                    $metadata->setDiscriminatorMap($discrMapAnnot->value);
                }
            }
        }


        // Evaluate DoctrineChangeTrackingPolicy annotation
        if (isset($classAnnotations['Doctrine\ORM\Mapping\ChangeTrackingPolicy'])) {
            $changeTrackingAnnot = $classAnnotations['Doctrine\ORM\Mapping\ChangeTrackingPolicy'];
            $metadata->setChangeTrackingPolicy(constant('Doctrine\ORM\Mapping\ClassMetadata::CHANGETRACKING_' . $changeTrackingAnnot->value));
        }

        // Evaluate annotations on properties/fields
        foreach ($class->getProperties() as $property) {
            if ($metadata->isMappedSuperclass && ! $property->isPrivate()
                ||
                $metadata->isInheritedField($property->name)
                ||
                $metadata->isInheritedAssociation($property->name)) {
                continue;
            }

            $mapping = array();
            $mapping['fieldName'] = $property->getName();

            // Check for JoinColummn/JoinColumns annotations
            $joinColumns = array();

            if ($joinColumnAnnot = $this->_reader->getPropertyAnnotation($property, 'Doctrine\ORM\Mapping\JoinColumn')) {
                $joinColumns[] = array(
                    'name' => $joinColumnAnnot->name,
                    'referencedColumnName' => $joinColumnAnnot->referencedColumnName,
                    'unique' => $joinColumnAnnot->unique,
                    'nullable' => $joinColumnAnnot->nullable,
                    'onDelete' => $joinColumnAnnot->onDelete,
                    'columnDefinition' => $joinColumnAnnot->columnDefinition,
                );
            } else if ($joinColumnsAnnot = $this->_reader->getPropertyAnnotation($property, 'Doctrine\ORM\Mapping\JoinColumns')) {
                foreach ($joinColumnsAnnot->value as $joinColumn) {
                    $joinColumns[] = array(
                        'name' => $joinColumn->name,
                        'referencedColumnName' => $joinColumn->referencedColumnName,
                        'unique' => $joinColumn->unique,
                        'nullable' => $joinColumn->nullable,
                        'onDelete' => $joinColumn->onDelete,
                        'columnDefinition' => $joinColumn->columnDefinition,
                    );
                }
            }

            // Field can only be annotated with one of:
            // @Column, @OneToOne, @OneToMany, @ManyToOne, @ManyToMany
            if ($columnAnnot = $this->_reader->getPropertyAnnotation($property, 'Doctrine\ORM\Mapping\Column')) {
                if ($columnAnnot->type == null) {
                    throw MappingException::propertyTypeIsRequired($className, $property->getName());
                }

                $mapping['type'] = $columnAnnot->type;
                $mapping['length'] = $columnAnnot->length;
                $mapping['precision'] = $columnAnnot->precision;
                $mapping['scale'] = $columnAnnot->scale;
                $mapping['nullable'] = $columnAnnot->nullable;
                $mapping['unique'] = $columnAnnot->unique;
                if ($columnAnnot->options) {
                    $mapping['options'] = $columnAnnot->options;
                }

                if (isset($columnAnnot->name)) {
                    $mapping['columnName'] = $columnAnnot->name;
                }

                if (isset($columnAnnot->columnDefinition)) {
                    $mapping['columnDefinition'] = $columnAnnot->columnDefinition;
                }

                if ($idAnnot = $this->_reader->getPropertyAnnotation($property, 'Doctrine\ORM\Mapping\Id')) {
                    $mapping['id'] = true;
                }

                if ($generatedValueAnnot = $this->_reader->getPropertyAnnotation($property, 'Doctrine\ORM\Mapping\GeneratedValue')) {
                    $metadata->setIdGeneratorType(constant('Doctrine\ORM\Mapping\ClassMetadata::GENERATOR_TYPE_' . $generatedValueAnnot->strategy));
                }

                if ($versionAnnot = $this->_reader->getPropertyAnnotation($property, 'Doctrine\ORM\Mapping\Version')) {
                    $metadata->setVersionMapping($mapping);
                }

                $metadata->mapField($mapping);

                // Check for SequenceGenerator/TableGenerator definition
                if ($seqGeneratorAnnot = $this->_reader->getPropertyAnnotation($property, 'Doctrine\ORM\Mapping\SequenceGenerator')) {
                    $metadata->setSequenceGeneratorDefinition(array(
                        'sequenceName' => $seqGeneratorAnnot->sequenceName,
                        'allocationSize' => $seqGeneratorAnnot->allocationSize,
                        'initialValue' => $seqGeneratorAnnot->initialValue
                    ));
                } else if ($tblGeneratorAnnot = $this->_reader->getPropertyAnnotation($property, 'Doctrine\ORM\Mapping\TableGenerator')) {
                    throw MappingException::tableIdGeneratorNotImplemented($className);
                }
            } else if ($oneToOneAnnot = $this->_reader->getPropertyAnnotation($property, 'Doctrine\ORM\Mapping\OneToOne')) {
                if ($idAnnot = $this->_reader->getPropertyAnnotation($property, 'Doctrine\ORM\Mapping\Id')) {
                    $mapping['id'] = true;
                }

                $mapping['targetEntity'] = $oneToOneAnnot->targetEntity;
                $mapping['joinColumns'] = $joinColumns;
                $mapping['mappedBy'] = $oneToOneAnnot->mappedBy;
                $mapping['inversedBy'] = $oneToOneAnnot->inversedBy;
                $mapping['cascade'] = $oneToOneAnnot->cascade;
                $mapping['orphanRemoval'] = $oneToOneAnnot->orphanRemoval;
                $mapping['fetch'] = $this->getFetchMode($className, $oneToOneAnnot->fetch);
                $metadata->mapOneToOne($mapping);
            } else if ($oneToManyAnnot = $this->_reader->getPropertyAnnotation($property, 'Doctrine\ORM\Mapping\OneToMany')) {
                $mapping['mappedBy'] = $oneToManyAnnot->mappedBy;
                $mapping['targetEntity'] = $oneToManyAnnot->targetEntity;
                $mapping['cascade'] = $oneToManyAnnot->cascade;
                $mapping['indexBy'] = $oneToManyAnnot->indexBy;
                $mapping['orphanRemoval'] = $oneToManyAnnot->orphanRemoval;
                $mapping['fetch'] = $this->getFetchMode($className, $oneToManyAnnot->fetch);

                if ($orderByAnnot = $this->_reader->getPropertyAnnotation($property, 'Doctrine\ORM\Mapping\OrderBy')) {
                    $mapping['orderBy'] = $orderByAnnot->value;
                }

                $metadata->mapOneToMany($mapping);
            } else if ($manyToOneAnnot = $this->_reader->getPropertyAnnotation($property, 'Doctrine\ORM\Mapping\ManyToOne')) {
                if ($idAnnot = $this->_reader->getPropertyAnnotation($property, 'Doctrine\ORM\Mapping\Id')) {
                    $mapping['id'] = true;
                }

                $mapping['joinColumns'] = $joinColumns;
                $mapping['cascade'] = $manyToOneAnnot->cascade;
                $mapping['inversedBy'] = $manyToOneAnnot->inversedBy;
                $mapping['targetEntity'] = $manyToOneAnnot->targetEntity;
                $mapping['fetch'] = $this->getFetchMode($className, $manyToOneAnnot->fetch);
                $metadata->mapManyToOne($mapping);
            } else if ($manyToManyAnnot = $this->_reader->getPropertyAnnotation($property, 'Doctrine\ORM\Mapping\ManyToMany')) {
                $joinTable = array();

                if ($joinTableAnnot = $this->_reader->getPropertyAnnotation($property, 'Doctrine\ORM\Mapping\JoinTable')) {
                    $joinTable = array(
                        'name' => $joinTableAnnot->name,
                        'schema' => $joinTableAnnot->schema
                    );

                    foreach ($joinTableAnnot->joinColumns as $joinColumn) {
                        $joinTable['joinColumns'][] = array(
                            'name' => $joinColumn->name,
                            'referencedColumnName' => $joinColumn->referencedColumnName,
                            'unique' => $joinColumn->unique,
                            'nullable' => $joinColumn->nullable,
                            'onDelete' => $joinColumn->onDelete,
                            'columnDefinition' => $joinColumn->columnDefinition,
                        );
                    }

                    foreach ($joinTableAnnot->inverseJoinColumns as $joinColumn) {
                        $joinTable['inverseJoinColumns'][] = array(
                            'name' => $joinColumn->name,
                            'referencedColumnName' => $joinColumn->referencedColumnName,
                            'unique' => $joinColumn->unique,
                            'nullable' => $joinColumn->nullable,
                            'onDelete' => $joinColumn->onDelete,
                            'columnDefinition' => $joinColumn->columnDefinition,
                        );
                    }
                }

                $mapping['joinTable'] = $joinTable;
                $mapping['targetEntity'] = $manyToManyAnnot->targetEntity;
                $mapping['mappedBy'] = $manyToManyAnnot->mappedBy;
                $mapping['inversedBy'] = $manyToManyAnnot->inversedBy;
                $mapping['cascade'] = $manyToManyAnnot->cascade;
                $mapping['indexBy'] = $manyToManyAnnot->indexBy;
                $mapping['orphanRemoval'] = $manyToManyAnnot->orphanRemoval;
                $mapping['fetch'] = $this->getFetchMode($className, $manyToManyAnnot->fetch);

                if ($orderByAnnot = $this->_reader->getPropertyAnnotation($property, 'Doctrine\ORM\Mapping\OrderBy')) {
                    $mapping['orderBy'] = $orderByAnnot->value;
                }

                $metadata->mapManyToMany($mapping);
            }
        }

        // Evaluate @HasLifecycleCallbacks annotation
        if (isset($classAnnotations['Doctrine\ORM\Mapping\HasLifecycleCallbacks'])) {
            foreach ($class->getMethods() as $method) {
                // filter for the declaring class only, callbacks from parents will already be registered.
                if ($method->isPublic() && $method->getDeclaringClass()->getName() == $class->name) {
                    $annotations = $this->_reader->getMethodAnnotations($method);

                    if ($annotations && is_numeric(key($annotations))) {
                        foreach ($annotations as $annot) {
                            $annotations[get_class($annot)] = $annot;
                        }
                    }

                    if (isset($annotations['Doctrine\ORM\Mapping\PrePersist'])) {
                        $metadata->addLifecycleCallback($method->getName(), \Doctrine\ORM\Events::prePersist);
                    }

                    if (isset($annotations['Doctrine\ORM\Mapping\PostPersist'])) {
                        $metadata->addLifecycleCallback($method->getName(), \Doctrine\ORM\Events::postPersist);
                    }

                    if (isset($annotations['Doctrine\ORM\Mapping\PreUpdate'])) {
                        $metadata->addLifecycleCallback($method->getName(), \Doctrine\ORM\Events::preUpdate);
                    }

                    if (isset($annotations['Doctrine\ORM\Mapping\PostUpdate'])) {
                        $metadata->addLifecycleCallback($method->getName(), \Doctrine\ORM\Events::postUpdate);
                    }

                    if (isset($annotations['Doctrine\ORM\Mapping\PreRemove'])) {
                        $metadata->addLifecycleCallback($method->getName(), \Doctrine\ORM\Events::preRemove);
                    }

                    if (isset($annotations['Doctrine\ORM\Mapping\PostRemove'])) {
                        $metadata->addLifecycleCallback($method->getName(), \Doctrine\ORM\Events::postRemove);
                    }

                    if (isset($annotations['Doctrine\ORM\Mapping\PostLoad'])) {
                        $metadata->addLifecycleCallback($method->getName(), \Doctrine\ORM\Events::postLoad);
                    }

                    if (isset($annotations['Doctrine\ORM\Mapping\PreFlush'])) {
                        $metadata->addLifecycleCallback($method->getName(), \Doctrine\ORM\Events::preFlush);
                    }
                }
            }
        }
    }




SOLUTION
Problem was with AnnotationReader which I forgot to set in /config/config.php.
The final /config/config.php is as following 

<?php
use Doctrine\Common\ClassLoader,
Doctrine\ORM\Configuration,
Doctrine\ORM\EntityManager,
Doctrine\Common\Cache\ArrayCache,
Doctrine\Common\Annotations\AnnotationReader,
Doctrine\ORM\Mapping\Driver\AnnotationDriver,
Doctrine\DBAL\Logging\EchoSqlLogger,
Doctrine\DBAL\Event\Listeners\MysqlSessionInit,
Doctrine\ORM\Tools\SchemaTool,
Doctrine\ORM\Tools\Setup,
Doctrine\Common\EventManager,
Gedmo\Timestampable\TimestampableListener,
Gedmo\Sluggable\SluggableListener,
Gedmo\Tree\TreeListener,
Gedmo\SoftDeleteable\SoftDeleteableListener,
Gedmo\Loggable\LoggableListener;

 include_once(dirname(__FILE__) . '/database.php');
 include_once 'app/thirdparty/Doctrine/Common/ClassLoader.php';
 include_once 'app/thirdparty/Doctrine/ORM/Tools/Setup.php';

 $APP_NAME = "TGCore";
 if($_SERVER['HTTP_HOST'] == "localhost"){
  $_CONFIG['base_url']   = "http://localhost/{$APP_NAME}/";
     $_CONFIG['base_path']   = $_SERVER['DOCUMENT_ROOT'] . "/{$APP_NAME}/";
 }else{
  $_CONFIG['base_url']   = "http://localhost/{$APP_NAME}/";
     $_CONFIG['base_path']   = $_SERVER['DOCUMENT_ROOT'] . "/{$APP_NAME}/";
 }

 define('ROOT_HOST', $_CONFIG['base_url']);
 define('ROOT_DIR', $_CONFIG['base_path']);

 /*********** Define the values *********/
 define("HOSTNAME", $db['hostname']);
 define("USERNAME", $db['username']);
 define("PASSWORD", $db['password']);
 define("DATABASE", $db['database']);
 define("BASE_URL", ROOT_HOST);


 $application_folder = 'app';
 define('APPPATH', ROOT_DIR.$application_folder.'/');

 define('EXT', '.php');

 /**
   *
   * @var Doctrine\ORM\EntityManager
   */
 $em = null;
 /*bootstrapping doctrine*/

 // Set up class loading
 $doctrineClassLoader = new ClassLoader('Doctrine',  APPPATH.'thirdparty');
 $doctrineClassLoader->register();

 // Set up Gedmo
 $classLoader = new ClassLoader('Gedmo', APPPATH.'thirdparty');
 $classLoader->register();

 // Set up zamoon extensions
 $zExtensionsLoader = new ClassLoader('z', APPPATH.'thirdparty');
 $zExtensionsLoader->register();

 // Set up models loading
 $entitiesClassLoader = new ClassLoader('models', APPPATH);
 $entitiesClassLoader->register();

 $isDevMode = true;

 $proxiesClassLoader = new ClassLoader('Proxies', APPPATH.'models/proxies');
 $proxiesClassLoader->register();

  $ormConfig = new Doctrine\ORM\Configuration;
  /*************************************** 1 ******************************************/
  //print ("ensure standard doctrine annotations are registered<br/>");
  Doctrine\Common\Annotations\AnnotationRegistry::registerFile(APPPATH.'thirdparty/Doctrine/ORM/Mapping/Driver/DoctrineAnnotations.php');

  /*************************************** 2 ******************************************/
  // print("Set up caches<br/>");
  $arrayCache = new Doctrine\Common\Cache\ArrayCache;
  $annotationReader = new Doctrine\Common\Annotations\AnnotationReader;
     $cachedAnnotationReader = new Doctrine\Common\Annotations\CachedReader(
      $annotationReader, // use reader
      $arrayCache             // and a cacheDriver
     );

      /*************************************** 3 ******************************************/
     // create a driver chain for metadata reading
     $driverChain = new Doctrine\ORM\Mapping\Driver\DriverChain();

     // load superclass metadata mapping only, into driver chain
     // also registers Gedmo annotations.NOTE: you can personalize it
     Gedmo\DoctrineExtensions::registerAbstractMappingIntoDriverChainORM(
      $driverChain,           // our metadata driver chain, to hook into
      $cachedAnnotationReader // our cached annotation reader
     );

      /*************************************** 4 ******************************************/
  // now we want to register our application entities,
  // for that we need another metadata driver used for Entity namespace
  $annotationDriver = new Doctrine\ORM\Mapping\Driver\AnnotationDriver(
     $cachedAnnotationReader, // our cached annotation reader
     array(APPPATH.'models/') // paths to look in
  );

  /*************************************** 5 ******************************************/
  // NOTE: driver for application Entity can be different, Yaml, Xml or whatever
  // register annotation driver for our application Entity namespace
  $driverChain->addDriver($annotationDriver, 'models');

  /*************************************** 6 ******************************************/
  // print("ORM Proxy configuration");
  $ormConfig->setProxyDir(APPPATH.'/models/proxies');
  $ormConfig->setProxyNamespace('Proxies');
  $ormConfig->setAutoGenerateProxyClasses(TRUE); // this can be based on production config.
  // register metadata driver
  $ormConfig->setMetadataDriverImpl($driverChain);
  // use our allready initialized cache driver
  $ormConfig->setMetadataCacheImpl($arrayCache);
  $ormConfig->setQueryCacheImpl($arrayCache);

  //$driverImpl = $ormConfig->newDefaultAnnotationDriver(array(APPPATH.'models/'));


           /*************************************** 7 ******************************************/

  $evm = new Doctrine\Common\EventManager();

  //print("gedmo extension listeners");
  // sluggable
  $sluggableListener = new Gedmo\Sluggable\SluggableListener;
  // you should set the used annotation reader to listener, to avoid creating new one for mapping drivers
  $sluggableListener->setAnnotationReader($cachedAnnotationReader);
  $evm->addEventSubscriber($sluggableListener);

  //loggable
  $loggableListener = new Gedmo\Loggable\LoggableListener;
  $loggableListener->setAnnotationReader($cachedAnnotationReader);
  $evm->addEventSubscriber($loggableListener);


  // timestampable
  $timestampableListener = new Gedmo\Timestampable\TimestampableListener;
  $timestampableListener->setAnnotationReader($cachedAnnotationReader);
  $evm->addEventSubscriber($timestampableListener);



  //soft delete
  $softdeletelistener = new Gedmo\SoftDeleteable\SoftDeleteableListener;
  $softdeletelistener->setAnnotationReader($cachedAnnotationReader);
  $evm->addEventSubscriber($softdeletelistener);

  //setup soft delete filter
  $ormConfig->addFilter('soft-deleteable', 'Gedmo\SoftDeleteable\Filter\SoftDeleteableFilter');

  // Database connection information
  $connectionOptions = array(
        'driver' => 'pdo_mysql',
        'user' =>     "root",
        'password' => "mysql",
        'host' =>     "localhost",
        'dbname' =>   "TG"
  );
 //central access point to ORM functionality.
  $em = EntityManager::create($connectionOptions, $ormConfig, $evm);
  //create/drop/update database schemas based on  <tt>ClassMetadata</tt> class descriptors.
  $tool = new SchemaTool($em);
  if($em){
   //ORM metadata descriptor for a class.
   $schemas = array(   $em->getClassMetadata('models\Country')
                   );

  }
  //Create the databaseschema for the given array of ClassMetadata instances.
  $tool->createSchema($schemas);
 /* End of file config.php */
 /* Location: ./appl/config/config.php */




REFERENCES
1 - Integrating Doctrine 2 with CodeIgniter 2, available at http://wildlyinaccurate.com/integrating-doctrine-2-with-codeigniter-2

2 - Setting up CodeIgniter 2 with Doctrine 2 the right way, available at http://www.joelverhagen.com/blog/2011/05/setting-up-codeigniter-2-with-doctrine-2-the-right-way/

3 - CodeIgniter-2-with-Doctrine-2, available at https://github.com/iPrayag/CodeIgniter-2-with-Doctrine-2/blob/master/application/libraries/Doctrine.php

4 - Using Doctrine with Code Igniter, available https://github.com/EllisLab/CodeIgniter/wiki/Using-Doctrine-with-Code-Igniter

5- Integrating with CodeIgniter, available at http://docs.doctrine-project.org/en/2.1/cookbook/integrating-with-codeigniter.html

6 - CodeIgniter 2 Doctrine 2 Integration, available at http://searchdaily.net/codeigniter-2-doctrine-2-integration/


No comments:

Post a Comment