/** * (non-PHPdoc) * @see core_kernel_persistence_ClassInterface::createProperty() */ public function createProperty(\core_kernel_classes_Class $resource, $label = '', $comment = '', $isLgDependent = false) { $returnValue = null; // First we reference the property in smooth mode because meta models always remain there. $smoothReturnValue = \core_kernel_persistence_smoothsql_Class::singleton()->createProperty($resource, $label, $comment, $isLgDependent); if ($smoothReturnValue) { $property = new \core_kernel_classes_Property($resource->getUri()); $column = array('name' => HardapiUtils::getShortName($smoothReturnValue)); $column['multi'] = $isLgDependent ? true : false; // If no range set, we assume it is a literal. $column['foreign'] = false; // We do not know the range yet. $referencer = ResourceReferencer::singleton(); $classLocations = $referencer->classLocations($resource); foreach ($classLocations as $loc) { $tblmgr = new TableManager($loc['table']); $tblmgr->addColumn($column); } $returnValue = $smoothReturnValue; $referencer->clearCaches(); } else { $uri = $resource->getUri(); throw new Exception("An error occured when creating property in smooth mode '{$uri}' before handling the hard sql aspect."); } return $returnValue; }
/** * Change a multi-valued property to a single-valued one. * * @access public * @author Jerome Bogaerts, <*****@*****.**> * @param Resource property The property to modifiy. * @param int batchSize Data must be transfered from the properties table to a given column. This parameter indicates the size of each pack of data transfered from the properties table to the column. * @return void */ public static function multipleToScalar(\core_kernel_classes_Resource $property, $batchSize = 100) { $referencer = ResourceReferencer::singleton(); $dbWrapper = \core_kernel_classes_DbWrapper::singleton(); $propertyDescription = self::propertyDescriptor($property); $propertyLocations = $referencer->propertyLocation($property); $propName = $propertyDescription['name']; $propUri = $property->getUri(); $propRanges = array(); foreach ($propertyDescription['range'] as $range) { // If no range provided, we assume it is a Literal. $propRanges[] = !empty($range) ? $range->getUri() : RDFS_LITERAL; } $offset = 0; foreach ($propertyLocations as $tblname) { $tblmgr = new TableManager($tblname); if ($tblmgr->exists()) { // Reset offset. $offset = 0; try { // We go from multiple to single. $toDelete = array(); // will contain ids of rows to delete in the 'properties table' after data transfer. // Add a column to the base table to receive single value. $baseTableName = str_replace('props', '', $tblname); $tblmgr->setName($baseTableName); $shortName = self::getShortName($property); $columnAdded = $tblmgr->addColumn(array('name' => $shortName, 'multi' => false)); if ($columnAdded == true) { // Now get the values in the props table. Group by instance ID in order to get only // one value to put in the target column. do { $hasResult = false; $retrievePropertyValue = empty($propRanges) || in_array(RDFS_LITERAL, $propRanges) ? true : false; $sql = 'SELECT "a"."id", "a"."instance_id", "a"."property_value", "a"."property_foreign_uri" FROM "' . $tblname . '" "a" '; $sql .= 'RIGHT JOIN (SELECT "instance_id", MIN("id") AS "id" FROM "' . $tblname . '" WHERE "property_uri" = ? '; $sql .= 'GROUP BY "instance_id") AS "b" ON ("a"."id" = "b"."id")'; $sql = $dbWrapper->limitStatement($sql, $batchSize, $offset); $result = $dbWrapper->query($sql, array($propUri)); // prepare the update statement. $sql = 'UPDATE "' . $baseTableName . '" SET "' . $shortName . '" = ? WHERE "id" = ?'; while ($row = $result->fetch()) { // Transfer to the 'base table'. $hasResult = true; $propertyValue = $retrievePropertyValue == true ? $row['property_value'] : $row['property_foreign_uri']; $dbWrapper->exec($sql, array($propertyValue, $row['instance_id'])); $toDelete[] = $row['id']; } $offset += $batchSize; } while ($hasResult === true); $inData = implode(',', $toDelete); $sql = 'DELETE FROM "' . $tblname . '" WHERE "id" IN (' . $inData . ')'; if ($dbWrapper->exec($sql) == 0) { // If an error occured or no rows removed, we // have a problem. $msg = "Cannot set multiplicity of Property '{$propUri}' because data transfered to the 'base table' could not be deleted"; throw new Exception($msg); } } else { $msg = "Cannot set multiplicity of Property '{$propUri}' because the corresponding 'base table' column could not be created."; throw new Exception($msg); } } catch (\PDOException $e) { $msg = "Cannot set multiplicity of Property '{$propUri}': " . $e->getMessage(); throw new Exception($msg); } } else { $msg = "Cannot set multiplicity of Property '{$propUri}' because the corresponding database location '{$tblname}' does not exist."; throw new Exception($msg); } } $referencer->clearCaches(); }