/** * Generate v5 UUID * * Version 5 UUIDs are named based. They require a namespace (another * valid UUID) and a value (the name). Given the same namespace and * name, the output is always the same. * * Note: if not set, the default namespace is a RESTo v4 UUID * generated at http://uuidgenerator.net/ * * @param string $name * @param uuid $namespace * * @author Andrew Moore * @link http://www.php.net/manual/en/function.uniqid.php#94959 */ public static function UUIDv5($name, $namespace = '92708059-2077-45a3-a4f3-1eb428789cff') { if (!RestoUtil::isValidUUID($namespace)) { return false; } // Get hexadecimal components of namespace $nhex = str_replace(array('-', '{', '}'), '', $namespace); // Binary Value $nstr = ''; // Convert Namespace UUID to bits for ($i = 0, $ii = strlen($nhex); $i < $ii; $i += 2) { $nstr .= chr(hexdec($nhex[$i] . $nhex[$i + 1])); } // Calculate hash value $hash = sha1($nstr . $name); return sprintf('%08s-%04s-%04x-%04x-%12s', substr($hash, 0, 8), substr($hash, 8, 4), hexdec(substr($hash, 12, 4)) & 0xfff | 0x5000, hexdec(substr($hash, 16, 4)) & 0x3fff | 0x8000, substr($hash, 20, 12)); }
/** * Store feature within {collection}.features table following the class model * * @param array $data : array (MUST BE GeoJSON in abstract Model) * @param RestoCollection $collection * */ public function storeFeature($data, $collection) { /* * Assume input file or stream is a JSON Feature */ if (!RestoGeometryUtil::isValidGeoJSONFeature($data)) { RestoLogUtil::httpError(500, 'Invalid feature description'); } /* * Remap properties between RESTo model and input * GeoJSON Feature file */ $properties = $this->mapInputProperties($data); /* * Add collection to $properties to initialize facet counts on collection */ $properties['collection'] = isset($properties['collection']) ? $properties['collection'] : $collection->name; /* * Compute unique identifier */ if (!isset($data['id']) || !RestoUtil::isValidUUID($data['id'])) { $featureIdentifier = $collection->toFeatureId(isset($properties['productIdentifier']) ? $properties['productIdentifier'] : md5(microtime() . rand())); } else { $featureIdentifier = $data['id']; } /* * First check if feature is already in database * (do this before getKeywords to avoid iTag process) */ if ($collection->context->dbDriver->check(RestoDatabaseDriver::FEATURE, array('featureIdentifier' => $featureIdentifier))) { RestoLogUtil::httpError(500, 'Feature ' . $featureIdentifier . ' already in database'); } /* * Tag module */ $keywords = array(); if (isset($collection->context->modules['Tag'])) { $tagger = RestoUtil::instantiate($collection->context->modules['Tag']['className'], array($collection->context, $collection->user)); $keywords = $tagger->getKeywords($properties, $data['geometry']); } /* * Store feature */ $collection->context->dbDriver->store(RestoDatabaseDriver::FEATURE, array('collection' => $collection, 'featureArray' => array('type' => 'Feature', 'id' => $featureIdentifier, 'geometry' => $data['geometry'], 'properties' => array_merge($properties, array('keywords' => $keywords))))); return new RestoFeature($collection->context, $collection->user, array('featureIdentifier' => $featureIdentifier)); }
/** * * Prepare an SQL WHERE clause from input filterName * * @param RestoModel $model (with model keys) * @param array $requestParams (with model keys) * @param string $filterName * @param boolean $exclusion : if true, exclude instead of include filter (WARNING ! only works for geometry and keywords) * */ private function prepareFilterQuery($model, $requestParams, $filterName, $exclusion = false) { /* * Special case - dates */ if ($model->getDbType($model->searchFilters[$filterName]['key']) === 'date') { return $this->prepareFilterQuery_date($model, $filterName, $requestParams); } /* * Special case identifier - use productIdentifier or identifier */ if ($filterName === 'geo:uid' && !RestoUtil::isValidUUID($requestParams['geo:uid'])) { return $model->getDbKey('productIdentifier') . ' = \'' . pg_escape_string($requestParams['geo:uid']) . '\''; } /* * Prepare filter from operation */ switch ($model->searchFilters[$filterName]['operation']) { /* * Keywords i.e. searchTerms */ case 'keywords': return $this->prepareFilterQuery_keywords($model, $filterName, $requestParams, $exclusion); /* * Intersects i.e. geo:* */ /* * Intersects i.e. geo:* */ case 'intersects': return $this->prepareFilterQuery_intersects($model, $filterName, $requestParams, $exclusion); /* * Distance i.e. geo:lon, geo:lat and geo:radius */ /* * Distance i.e. geo:lon, geo:lat and geo:radius */ case 'distance': return $this->prepareFilterQuery_distance($model, $filterName, $requestParams, $exclusion); /* * Intervals */ /* * Intervals */ case 'interval': return $this->prepareFilterQuery_interval($model, $filterName, $requestParams); /* * Simple case - non 'interval' operation on value or arrays */ /* * Simple case - non 'interval' operation on value or arrays */ default: return $this->prepareFilterQuery_general($model, $filterName, $requestParams, $model->getDbType($model->searchFilters[$filterName]['key'])); } }