/**
  * Calling this method will transfer all instances of $class from the statements table
  * to specific optimized relational tables.
  * 
  * During optimization, the current user has all privileges on the persistent memory. At
  * the end of the process, the old privileges will be set back.
  * 
  * The $options array can contain the following key => values (all booleans):
  * 
  * - recursive: compile the target class and its subclasses (default: false).
  * - append: append data to the existing optimized table if it already exists (default: false).
  * - rmSources: remove the triples in the statement table after transfer (default: true).
  *
  * @access public
  * @author Bertrand Chevrier, <*****@*****.**>
  * @param  \core_kernel_classes_Class class
  * @param  array options
  * @return boolean Will return true if it succeeds, false otherwise.
  */
 public function hardify(\core_kernel_classes_Class $class, $options = array())
 {
     $returnValue = (bool) false;
     $oldUpdatableModels = core_kernel_persistence_smoothsql_SmoothModel::getUpdatableModelIds();
     try {
         // Give access to all models during hardification.
         core_kernel_persistence_smoothsql_SmoothModel::forceUpdatableModelIds(self::getAllModelIds());
         $classLabel = $class->getLabel();
         \common_Logger::i("Hardifying class {$classLabel}", array("GENERIS"));
         if (defined("DEBUG_PERSISTENCE") && DEBUG_PERSISTENCE) {
             if (in_array($class->getUri(), self::$debug_tables)) {
                 return;
             }
             \common_Logger::d('hardify ' . $class->getUri());
             self::$debug_tables[] = $class->getUri();
             $countStatement = $this->countStatements();
         }
         if (in_array($class->getUri(), self::$blackList)) {
             return $returnValue;
         }
         // ENTER IN SMOOTH SQL MODE
         PersistenceProxy::forceMode(PERSISTENCE_SMOOTH);
         //recursive will hardify the class and it's subclasses in the same table!
         isset($options['recursive']) ? $recursive = $options['recursive'] : ($recursive = false);
         //createForeigns will hardify the class that are range of the properties
         isset($options['createForeigns']) ? $createForeigns = $options['createForeigns'] : ($createForeigns = false);
         //check if we append the data in case the hard table exists or truncate the table and add the new rows
         isset($options['append']) ? $append = $options['append'] : ($append = false);
         //if true, the instances of the class will  be removed from the statements table!
         isset($options['rmSources']) ? $rmSources = (bool) $options['rmSources'] : ($rmSources = false);
         //if defined, we took all the properties of the class and it's parents till the topclass
         isset($options['topclass']) ? $topclass = $options['topclass'] : ($topclass = new \core_kernel_classes_Class(RDFS_RESOURCE));
         //if defined, compile the additional properties
         isset($options['additionalProperties']) ? $additionalProperties = $options['additionalProperties'] : ($additionalProperties = array());
         //if defined, reference the additional class to the table
         isset($options['referencesAllTypes']) ? $referencesAllTypes = $options['referencesAllTypes'] : ($referencesAllTypes = false);
         $tableName = '_' . Utils::getShortName($class);
         $myTableMgr = new TableManager($tableName);
         $referencer = ResourceReferencer::singleton();
         //get the table columns from the class properties
         $columns = array();
         $ps = new PropertySwitcher($class);
         $properties = $ps->getProperties($additionalProperties);
         $columns = $ps->getTableColumns($additionalProperties, self::$blackList);
         //init the count value in hardened classes:
         if (isset($this->hardenedClasses[$class->getUri()])) {
             PersistenceProxy::restoreImplementation();
             return true;
             //already being compiled
         } else {
             $this->hardenedClasses[$class->getUri()] = 0;
         }
         if (!$append || $append && !$myTableMgr->exists()) {
             //create the table
             if ($myTableMgr->exists()) {
                 $myTableMgr->remove();
             }
             $myTableMgr->create($columns);
             //reference the class
             $referencer->referenceClass($class, array("topclass" => $topclass, "additionalProperties" => $additionalProperties));
             if ($referencesAllTypes) {
                 $referencer->referenceInstanceTypes($class);
             }
         }
         //insert the resources
         $startIndex = 0;
         $instancePackSize = 100;
         $instances = $class->getInstances(false, array('offset' => $startIndex, 'limit' => $instancePackSize));
         $count = count($instances);
         $notDeletedInstances = array();
         do {
             //reset timeout:
             //set_time_limit(30);
             \helpers_TimeOutHelper::setTimeOutLimit(\helpers_TimeOutHelper::MEDIUM);
             $rows = array();
             foreach ($instances as $index => $resource) {
                 if ($referencer->isResourceReferenced($resource)) {
                     PersistenceProxy::forceMode(PERSISTENCE_HARD);
                     $resource->delete();
                     PersistenceProxy::restoreImplementation();
                 }
                 $row = array('uri' => $resource->getUri());
                 foreach ($properties as $property) {
                     $propValue = $resource->getOnePropertyValue($property);
                     $row[Utils::getShortName($property)] = $propValue;
                 }
                 $rows[] = $row;
             }
             $rowMgr = new RowManager($tableName, $columns);
             $rowMgr->insertRows($rows);
             foreach ($instances as $resource) {
                 $referencer->referenceResource($resource, $tableName, null, true);
                 if ($rmSources) {
                     //remove exported resources in smooth sql, if required:
                     // Be carefull, the resource can still exist even if
                     // delete returns true. Indeed, modelIds can be mixed between
                     // multiple models and only a part of the triples that consitute
                     // the resource might have been deleted.
                     if (!$resource->delete() || $resource->exists()) {
                         //@TODO : modified resource::delete() because resource not in local modelId cannot be deleted
                         $notDeletedInstances[] = $resource->getUri();
                         $startIndex++;
                     }
                 }
             }
             if (!$rmSources) {
                 //increment start index only if not removed
                 $startIndex += $instancePackSize;
             }
             //record hardened instances number
             if (isset($this->hardenedClasses[$class->getUri()])) {
                 $this->hardenedClasses[$class->getUri()] += $count;
             } else {
                 $this->hardenedClasses[$class->getUri()] = $count;
             }
             //update instance array and count value
             $instances = $class->getInstances(false, array('offset' => $startIndex, 'limit' => $instancePackSize));
             foreach ($notDeletedInstances as $uri) {
                 unset($instances[$uri]);
             }
             $count = count($instances);
             \helpers_TimeOutHelper::reset();
         } while ($count > 0);
         $returnValue = true;
         // Treat subclasses of the current class
         if ($recursive) {
             foreach ($class->getSubClasses(true) as $subClass) {
                 $returnValue = $this->hardify($subClass, array_merge($options, array('recursive' => false, 'append' => true)));
             }
         }
         //reset cache:
         $referencer->clearCaches();
         // EXIT SMOOTH SQL MODE
         PersistenceProxy::restoreImplementation();
         if (defined("DEBUG_PERSISTENCE") && DEBUG_PERSISTENCE) {
             $this->unhardify($class, array_merge($options, array('recursive' => false, 'removeForeigns' => false)));
             \common_Logger::d('unhardened result statements ' . $this->countStatements() . ' / ' . $countStatement);
         }
         // Give the normal rights on models to the session.
         core_kernel_persistence_smoothsql_SmoothModel::forceUpdatableModelIds($oldUpdatableModels);
     } catch (Exception $e) {
         \common_Logger::e('An error occured during hardification: ' . $e->getMessage());
         core_kernel_persistence_smoothsql_SmoothModel::forceUpdatableModelIds($oldUpdatableModels);
     }
     return (bool) $returnValue;
 }
 public function testForceMode()
 {
     $this->hardify();
     // Check if the returner implementation are correct
     PersistenceProxy::forceMode(PERSISTENCE_SMOOTH);
     $classProxy = ClassProxy::singleton();
     $impl = $classProxy->getImpToDelegateTo($this->targetSubjectClass);
     $this->assertTrue($impl instanceof core_kernel_persistence_smoothsql_Class);
     $this->assertEquals(count($this->targetSubjectClass->getInstances()), 1);
     $this->assertEquals(count($this->targetSubjectSubClass->getInstances()), 1);
     PersistenceProxy::restoreImplementation();
     $this->assertTrue(ClassProxy::singleton()->getImpToDelegateTo($this->targetSubjectClass) instanceof Clazz);
     $this->assertTrue(ResourceProxy::singleton()->getImpToDelegateTo($this->subject1) instanceof Resource);
 }
 /**
  * Retrieve the inplementation to delegate
  *
  * @access public
  * @author Joel Bout, <*****@*****.**>
  * @param  Resource resource
  * @param  array params
  * @return \core_kernel_persistence_ResourceInterface
  */
 public function getImpToDelegateTo(core_kernel_classes_Resource $resource, $params = array())
 {
     $returnValue = null;
     if (!isset(self::$ressourcesDelegatedTo[$resource->getUri()]) || PersistenceProxy::isForcedMode()) {
         $impls = $this->getAvailableImpl($params);
         foreach ($impls as $implName => $enable) {
             // If the implementation is enabled && the resource exists in this context
             if ($enable && $this->isValidContext($implName, $resource)) {
                 $implClass = self::$implClasses[$implName];
                 $reflectionMethod = new \ReflectionMethod($implClass, 'singleton');
                 $delegate = $reflectionMethod->invoke(null);
                 if (PersistenceProxy::isForcedMode()) {
                     return $delegate;
                 }
                 self::$ressourcesDelegatedTo[$resource->getUri()] = $delegate;
                 break;
             }
         }
     }
     if (isset(self::$ressourcesDelegatedTo[$resource->getUri()])) {
         $returnValue = self::$ressourcesDelegatedTo[$resource->getUri()];
     } else {
         $errorMessage = "The resource with uri {$resource->getUri()} does not exist in the available implementation(s): ";
         $i = 0;
         foreach ($this->getAvailableImpl() as $name => $valid) {
             if ($valid) {
                 if ($i > 0) {
                     $errorMessage .= ", ";
                 }
                 $errorMessage .= $name;
             }
             $i++;
         }
         throw new \core_kernel_persistence_Exception($errorMessage);
     }
     return $returnValue;
 }
 /**
  * Short description of method getImpToDelegateTo
  *
  * @access public
  * @author Jerome Bogaerts, <*****@*****.**>
  * @param  Resource resource
  * @param  array params
  * @return \core_kernel_persistence_ResourceInterface
  */
 public function getImpToDelegateTo(\core_kernel_classes_Resource $resource, $params = array())
 {
     if (!isset(self::$ressourcesDelegatedTo[$resource->getUri()]) || PersistenceProxy::isForcedMode()) {
         $impls = $this->getAvailableImpl($params);
         foreach ($impls as $implName => $enable) {
             // If the implementation is enabled && the resource exists in this context
             if ($enable && $this->isValidContext($implName, $resource)) {
                 $implClass = self::$implClasses[$implName];
                 $reflectionMethod = new \ReflectionMethod($implClass, 'singleton');
                 $delegate = $reflectionMethod->invoke(null);
                 if (PersistenceProxy::isForcedMode()) {
                     return $delegate;
                 }
                 self::$ressourcesDelegatedTo[$resource->getUri()] = $delegate;
                 break;
             }
         }
     }
     return self::$ressourcesDelegatedTo[$resource->getUri()];
 }
 public function testSearchInstancesHard($hard = true)
 {
     if (!$hard) {
         return;
     }
     PersistenceProxy::forceMode(PERSISTENCE_HARD);
     $class = new core_kernel_classes_Class('http://www.tao.lu/Ontologies/TAO.rdf#Languages');
     if (ResourceReferencer::singleton()->isClassReferenced($class)) {
         $propertyFilter = array(RDFS_LABEL => 'English');
         $options = array('like' => false, 'recursive' => 0);
         $languagesDependantProp = $class->searchInstances($propertyFilter, $options);
         $found = count($languagesDependantProp);
         $this->assertTrue($found > 0);
         $propertyFilter = array(RDF_VALUE => 'EN', RDF_TYPE => 'http://www.tao.lu/Ontologies/TAO.rdf#Languages');
         $languagesDependantProp = $class->searchInstances($propertyFilter, $options);
         $nfound = count($languagesDependantProp);
         $this->assertTrue($nfound > 0);
         $this->assertEquals($found, $nfound);
     }
     PersistenceProxy::restoreImplementation();
 }