/**
  * Test the HarApi utils class
  * @see Utils
  */
 public function testUtils()
 {
     $class = new core_kernel_classes_Class(CLASS_ROLE);
     $shortName = Utils::getShortName($class);
     $this->assertEquals($shortName, "06ClassRole");
     $longName = Utils::getLongName($shortName);
     $this->assertEquals($longName, $class->getUri());
 }
 /**
  * Short description of method loadProperties
  *
  * @access private
  * @author Joel Bout, <*****@*****.**>
  * @param  boolean force
  * @param  array additionalProperties
  * @return mixed
  */
 private function loadProperties($force = false, $additionalProperties = array())
 {
     if (is_null(self::$_properties) || $force) {
         if (!$force && $this->cacheModes['property'] == self::CACHE_FILE) {
             $serial = 'hard-api-property';
             try {
                 $cache = \common_cache_FileCache::singleton();
                 $properties = $cache->get($serial);
                 self::$_properties = $properties;
             } catch (\common_cache_NotFoundException $e) {
                 // The cache cannot be accessed, build the property cache.
                 // get all the compiled tables
                 $dbWrapper = \core_kernel_classes_DbWrapper::singleton();
                 $tables = array();
                 $query = 'SELECT DISTINCT "id","table" FROM "class_to_table"';
                 $result = $dbWrapper->query($query);
                 while ($row = $result->fetch()) {
                     $tables[$row['id']] = $row['table'];
                 }
                 $additionalPropertiesTable = array();
                 $query = 'SELECT DISTINCT "class_id","property_uri" FROM "class_additional_properties"';
                 $result = $dbWrapper->query($query);
                 while ($row = $result->fetch()) {
                     $additionalPropertiesTable[$row['class_id']][] = new \core_kernel_classes_Property($row['property_uri']);
                 }
                 //retrieve each property by table
                 $this->loadClasses();
                 self::$_properties = array();
                 foreach ($tables as $classId => $table) {
                     //check in $additionalPropertiesTable if current table is concerned by additionnal properties
                     if (isset($additionalPropertiesTable[$classId])) {
                         $additionalProperties = $additionalPropertiesTable[$classId];
                     } else {
                         $additionalProperties = array();
                     }
                     $classUri = Utils::getLongName($table);
                     $class = new \core_kernel_classes_Class($classUri);
                     $topclassUri = self::$_classes[$classUri]['topclass'];
                     $topclass = new \core_kernel_classes_Class($topclassUri);
                     $ps = new PropertySwitcher($class, $topclass);
                     $properties = $ps->getProperties($additionalProperties);
                     foreach ($properties as $property) {
                         $propertyUri = $property->getUri();
                         if ($property->isMultiple() || $property->isLgDependent()) {
                             if (isset(self::$_properties[$propertyUri])) {
                                 if (!in_array("{$table}props", self::$_properties[$propertyUri])) {
                                     self::$_properties[$propertyUri][] = "{$table}props";
                                 }
                             } else {
                                 self::$_properties[$propertyUri] = array("{$table}props");
                             }
                         } else {
                             if (isset(self::$_properties[$propertyUri])) {
                                 if (!in_array("{$table}", self::$_properties[$propertyUri])) {
                                     self::$_properties[$propertyUri][] = "{$table}";
                                 }
                             } else {
                                 self::$_properties[$propertyUri] = array("{$table}");
                             }
                         }
                     }
                 }
                 //saving the properties in the cache file
                 try {
                     $cache = \common_cache_FileCache::singleton();
                     $cache->put(self::$_properties, $serial);
                 } catch (\common_cache_Exception $e) {
                     throw new Exception("cannot write the required property cache file for serial '{$serial}'.");
                 }
             }
         }
     }
 }
 /**
  * Short description of method duplicate
  *
  * @access public
  * @author Joel Bout, <*****@*****.**>
  * @param  Resource resource
  * @param  array excludedProperties
  * @return \core_kernel_classes_Resource
  */
 public function duplicate(\core_kernel_classes_Resource $resource, $excludedProperties = array())
 {
     $returnValue = null;
     $referencer = ResourceReferencer::singleton();
     $tableName = $referencer->resourceLocation($resource);
     if (empty($tableName)) {
         return $returnValue;
     }
     //the new Uri
     $newUri = \common_Utils::getNewUri();
     $dbWrapper = \core_kernel_classes_DbWrapper::singleton();
     //duplicate the row in the main table
     $query = 'SELECT * FROM "' . $tableName . '" WHERE "uri" = ?';
     $result = $dbWrapper->query($query, array($resource->getUri()));
     $rows = $result->fetchAll();
     if (count($rows) > 0) {
         //get the columns to duplicate
         $columnProps = array();
         for ($i = 0; $i < $result->columnCount(); $i++) {
             $column = $result->getColumnMeta($i);
             if (preg_match("/^[0-9]{2,}/", $column['name'])) {
                 $propertyUri = HardapiUtils::getLongName($column['name']);
                 if (!in_array($propertyUri, $excludedProperties)) {
                     //check if the property is excluded
                     $columnProps[$propertyUri] = $column['name'];
                 }
             }
         }
         // Fetch the first result.
         $instanceId = $rows[0]['id'];
         //build the insert query
         $insertQuery = 'INSERT INTO "' . $tableName . '" ("uri"';
         foreach ($columnProps as $column) {
             if (!is_string($column)) {
                 throw new Exception('columns should be a string');
             }
             $insertQuery .= ', "' . $column . '"';
         }
         $insertQuery .= ') VALUES (';
         $insertQuery .= "'{$newUri}'";
         foreach ($columnProps as $column) {
             $insertQuery .= ", '" . $rows[0][$column] . "'";
         }
         $insertQuery .= ')';
         $insertResult = $dbWrapper->exec($insertQuery);
         if ($insertResult !== false && $instanceId > -1) {
             //duplicated data
             $duplicatedResource = new \core_kernel_classes_Resource($newUri);
             $referencer->referenceResource($duplicatedResource, $tableName, $resource->getTypes(), true);
             $duplicateInstanceId = Utils::getInstanceId($duplicatedResource);
             //now we duplciate the rows of the Props table
             //linearize the excluded properties
             $excludedPropertyList = '';
             foreach ($excludedProperties as $excludedProperty) {
                 $excludedPropertyList .= "'{$excludedProperty}',";
             }
             $excludedPropertyList = substr($excludedPropertyList, 0, strlen($excludedPropertyList) - 1);
             //query templates of the 3 ways to insert the props rows
             $insertPropValueQuery = 'INSERT INTO "' . $tableName . 'props" ("property_uri", "property_value", "l_language", "instance_id") VALUES (?,?,?,?)';
             $insertPropForeignQuery = 'INSERT INTO "' . $tableName . 'props" ("property_uri", "property_foreign_uri", "l_language", "instance_id") VALUES (?,?,?,?)';
             $insertPropEmptyQuery = 'INSERT INTO "' . $tableName . 'props" ("property_uri", "l_language", "instance_id") VALUES (?,?,?)';
             //get the rows to duplicate
             try {
                 $propsQuery = 'SELECT * FROM "' . $tableName . 'props" WHERE "instance_id" = ? ';
                 $propsQuery .= empty($excludedPropertyList) ? '' : ' AND "property_uri" NOT IN (' . $excludedPropertyList . ') ';
                 $propsResult = $dbWrapper->query($propsQuery, array($instanceId));
             } catch (\PDOException $e) {
                 throw new Exception("Unable to duplicate the resource {$resource->getUri()} : " . $e->getMessage());
             }
             while ($row = $propsResult->fetch()) {
                 $propUri = $row['property_uri'];
                 $propValue = $row['property_value'];
                 $propForeign = $row['property_foreign_uri'];
                 $proplang = $row['l_language'];
                 //insert them regarding the populated columns
                 if (!is_null($propValue) && !empty($propValue)) {
                     $dbWrapper->exec($insertPropValueQuery, array($propUri, $propValue, $proplang, $duplicateInstanceId));
                 } else {
                     if (!is_null($propForeign) && !empty($propForeign)) {
                         $dbWrapper->exec($insertPropForeignQuery, array($propUri, $propForeign, $proplang, $duplicateInstanceId));
                     } else {
                         $dbWrapper->exec($insertPropEmptyQuery, array($propUri, $proplang, $duplicateInstanceId));
                         //costly to insert NULL values
                     }
                 }
             }
             //return the duplciated resource
             $returnValue = $duplicatedResource;
         }
     }
     return $returnValue;
 }
    /**
     * Unhardify a specific class. Unhardifying a class implies that the instances of this
     * class will be transfered from specific optimized tables to the statement table, as RDF
     * triples.
     * 
     * The $options array is an associative array where values are all booleans. The keys that
     * can be used to pass specific unhardify options are the following:
     * 
     * - recursive: Unhardify the target class and its subclasses (default: false).
     *
     * @access public
     * @author Cédric Alfonsi, <*****@*****.**>
     * @param  \core_kernel_classes_Class class
     * @param  array options
     * @return boolean true if the resource was correctly unhardified, false otherwise.
     */
    public function unhardify(\core_kernel_classes_Class $class, $options = array())
    {
        $returnValue = (bool) false;
        $classLabel = $class->getLabel();
        \common_Logger::i("Unhardifying class {$classLabel}", 'GENERIS');
        if (defined("DEBUG_PERSISTENCE") && DEBUG_PERSISTENCE) {
            var_dump('unhardify ' . $class->getUri());
        }
        // Check if the class has been hardened
        if (!ResourceReferencer::singleton()->isClassReferenced($class)) {
            \common_Logger::w("Class {$classLabel} could not be unhardened because it is not hardified.");
            return false;
        }
        //if defined, we take all the properties of the class and it's parents till the topclass
        $classLocations = ResourceReferencer::singleton()->classLocations($class);
        $topclass = null;
        if (count($classLocations) > 1) {
            throw new Exception("Try to unhardify the class {$class->getUri()} which has multiple locations");
        } else {
            $topclass = new \core_kernel_classes_Class($classLocations[0]['topclass']);
        }
        //recursive will unhardify the class and it's subclasses in the same table!
        isset($options['recursive']) ? $recursive = $options['recursive'] : ($recursive = false);
        //removeForeigns will unhardify the class that are range of the properties
        isset($options['removeForeigns']) ? $removeForeigns = $options['removeForeigns'] : ($removeForeigns = false);
        //rmSources will remove the related data from the hard data after
        //transfer to the smooth data.
        $rmSources = true;
        // Get class' properties
        $propertySwitcher = new PropertySwitcher($class);
        $additionalProperties = array();
        $properties = $propertySwitcher->getProperties($additionalProperties);
        $columns = $propertySwitcher->getTableColumns($additionalProperties, self::$blackList);
        // Get all instances of this class
        $startIndex = 0;
        $instancePackSize = 100;
        $instances = $class->getInstances(false, array('offset' => $startIndex, 'limit' => $instancePackSize));
        $count = count($instances);
        $existingInstances = array();
        do {
            //reset timeout:
            \helpers_TimeOutHelper::setTimeOutLimit(\helpers_TimeOutHelper::MEDIUM);
            // lionel did that :d le salop
            PersistenceProxy::forceMode(PERSISTENCE_SMOOTH);
            foreach ($instances as $uri => $instance) {
                if ($instance->exists()) {
                    PersistenceProxy::forceMode(PERSISTENCE_HARD);
                    $instance->delete();
                    PersistenceProxy::restoreImplementation();
                    unset($instances[$uri]);
                    $existingInstances[] = $uri;
                }
            }
            PersistenceProxy::restoreImplementation();
            foreach ($instances as $instance) {
                // Get table name where the resource is located
                $tableName = ResourceReferencer::singleton()->resourceLocation($instance);
                // Get Instance type
                $types = $instance->getTypes();
                // Create instance in the smooth implementation
                PersistenceProxy::forceMode(PERSISTENCE_SMOOTH);
                $class->createInstance('', '', $instance->getUri());
                // set types to the newly created instance
                foreach ($types as $type) {
                    if (!$type->equals($class)) {
                        $instance->setType($type);
                    }
                }
                PersistenceProxy::restoreImplementation();
                // Export properties of the instance
                foreach ($columns as $column) {
                    $property = new \core_kernel_classes_Property(Utils::getLongName($column['name']));
                    // Multiple property
                    if (isset($column['multi']) && $column['multi']) {
                        $sqlQuery = 'SELECT
								"' . $tableName . 'props"."property_value",
								"' . $tableName . 'props"."property_foreign_uri", 
								"' . $tableName . 'props"."l_language" 
							FROM "' . $tableName . 'props"
							LEFT JOIN "' . $tableName . '" ON "' . $tableName . '"."id" = "' . $tableName . 'props"."instance_id"
							WHERE "' . $tableName . '"."uri" = ? 
								AND "' . $tableName . 'props"."property_uri" = ?';
                        $dbWrapper = \core_kernel_classes_DbWrapper::singleton();
                        $sqlResult = $dbWrapper->query($sqlQuery, array($instance->getUri(), $property->getUri()));
                        if ($sqlResult->errorCode() !== '00000') {
                            throw new Exception("unable to unhardify : " . $dbWrapper->errorMessage());
                        }
                        // ENTER IN SMOOTH SQL MODE
                        PersistenceProxy::forceMode(PERSISTENCE_SMOOTH);
                        while ($row = $sqlResult->fetch()) {
                            $value = null;
                            if (!empty($row['property_value'])) {
                                $value = $row['property_value'];
                            } else {
                                $value = $row['property_foreign_uri'];
                            }
                            $lg = $row['l_language'];
                            if (!empty($lg)) {
                                $instance->setPropertyValueByLg($property, $value, $lg);
                            } else {
                                $instance->setPropertyValue($property, $value);
                            }
                        }
                        /// EXIT HARD SQL MODE
                        PersistenceProxy::restoreImplementation();
                    } else {
                        $value = $instance->getOnePropertyValue($property);
                        if ($value != null) {
                            PersistenceProxy::forceMode(PERSISTENCE_SMOOTH);
                            $instance->setPropertyValue($property, $value);
                            PersistenceProxy::restoreImplementation();
                        }
                    }
                }
                // delete instance in the hard implementation
                $instance->delete();
            }
            //record decompiled instances number
            if (isset($this->decompiledClasses[$class->getUri()])) {
                $this->decompiledClasses[$class->getUri()] += $count;
            } else {
                $this->decompiledClasses[$class->getUri()] = $count;
            }
            //update instance array and count value
            $instances = $class->getInstances(false, array('offset' => $startIndex, 'limit' => $instancePackSize));
            foreach ($existingInstances as $uri) {
                unset($instances[$uri]);
            }
            $count = count($instances);
            \helpers_TimeOutHelper::reset();
        } while ($count > 0);
        // Unreference the class
        $returnValue = ResourceReferencer::singleton()->unReferenceClass($class);
        // If recursive, treat the subclasses
        if ($recursive) {
            foreach ($class->getSubClasses(true) as $subClass) {
                if (ResourceReferencer::singleton()->isClassReferenced($subClass)) {
                    $returnValue = $this->unhardify($subClass, $options);
                }
            }
        }
        return (bool) $returnValue;
    }