query) && ('WFS' != V::get('service', '', $request->query))) { throw new Api_WfsException("Only WFS Service is allowed"); } $req = V::get('REQUEST', '', $request->query); if (!empty($req)) { $methodName = "{$req}Action"; if (!method_exists($this, $methodName)) { throw new Api_WfsException("Not Implemented " . htmlspecialchars($req), 501); } $this->DBG("WfsServer->{$methodName}() ...", __LINE__); $document = $this->$methodName($urlQuery); } else { $this->DBG("WfsServer->parseXMLRequest() ...", __LINE__); $document = $this->parseXMLRequest(); header('Content-type: application/xml'); echo ''; echo $document; exit;// TODO: return $document; } IF(V::get('DBG','',$_GET)){echo'
$document (' . __CLASS__ . '::' . __FUNCTION__ . ':' . __LINE__ . '): ';print_r($document);echo'';}
if ('raw' == V::get('outputFormat', '', $request->query)) {
header('Content-type: text/plain; charset=utf-8');
echo $document;
} else {
header('Content-type: application/xml');
echo $document;
}
}
public function parseXMLRequest() {
$data = array();
$reqContent = Request::getRequestBody();
if (empty($reqContent)) {
throw new Exception("Empty request");
}
$parserXml = xml_parser_create();
xml_parser_set_option($parserXml, XML_OPTION_CASE_FOLDING, 0);
xml_parser_set_option($parserXml, XML_OPTION_SKIP_WHITE, 1);
if (0 == xml_parse_into_struct($parserXml, $reqContent, $tags)) {
throw new Exception("Error parsing xml");
}
xml_parser_free($parserXml);
if (empty($tags)) {
throw new Exception("Empty structure from request");
}
$rootTagName = V::get('tag', '', $tags[0]);
if ('Transaction' == $rootTagName) return $this->_parseTransactionXmlStruct($reqContent, $tags);
throw new Api_WfsException("Not implemented '{$rootTagName}' #L." . __LINE__, 501);
}
public function getFeatureAction() {
$args = $this->parseGetFeatureArgsFromRequest();
if ('hits' == $args['resultType']) {
return $this->getTotalFeatures($args, $simple = true);
} else {
return $this->getFeatures($args, $simple = true);
}
}
public function getFeatureAdvancedAction() {
$args = $this->parseGetFeatureArgsFromRequest();
if ('hits' == $args['resultType']) {
return $this->getTotalFeatures($args, $simple = false);
} else {
if ('/@instance' == strtolower(substr($args['typeName'], -1 * strlen('/@instance')))) {
return $this->getInstanceFeatures(substr($args['typeName'], 0, -1 * strlen('/@instance')), $args);
}
return $this->getFeatures($args, $simple = false);
}
}
public function testOgcFilterAction() {
$type = V::get('TYPENAME', '', $_REQUEST);
$typeEx = explode(':', $type);
$maxFeatures = V::get('MAXFEATURES', '10000', $_REQUEST, 'int');// TODO: Set Deafult Limit
$ogcFilter = V::get('Filter', '', $_REQUEST);
$srsname = V::get('SRSNAME', '', $_REQUEST);// eg. EPSG:4326
if (count($typeEx) == 2) {
Lib::loadClass('ParseOgcFilter');
$parser = new ParseOgcFilter();
$parser->loadOgcFilter($ogcFilter);
$queryWhereBuilder = $parser->convertToSqlQueryWhereBuilder();
echo $queryWhereBuilder->getQueryWhere('t');
} else {
throw new HttpException("Wrong param TYPENAME", 400);
}
}
public function getTotalFeatures($args, $simple = true) {
DBG::log("typeName({$args['xsd:type']})");
$acl = $this->getAclFromTypeName($args['xsd:type']);
DBG::log([ 'msg'=>"typeName({$args['xsd:type']}) - acl(".get_class($acl).")", '$acl'=>$acl ]);
$baseNsUri = Api_WfsNs::getBaseWfsUri();
$rootWfsNs = 'p5';
$rootWfsNsUri = "{$baseNsUri}";
$wfsNs = $args['typePrefix'];
$wfsNsUri = "{$baseNsUri}/" . ('p5_' == substr($args['typePrefix'], 0, 3)) ? substr($args['typePrefix'], 3) : $args['typePrefix'];
$featureTypeUri = $this->getBaseUri() . "?SERVICE=WFS&VERSION=1.0.0&TYPENAME={$args['xsd:type']}&REQUEST=DescribeFeatureType";
DBG::log("ogcFilter(" . strlen($args['ogc:filter']) . "): {$args['ogc:filter']}");
$searchParams = array();
$searchParams['limit'] = $args['limit'];
$searchParams['limitstart'] = $args['offset'];
if (!empty($args['sortBy'])) {
$searchParams['sortBy'] = $args['sortBy'];
} else {
$searchParams['order_by'] = $acl->getPrimaryKeyField();
$searchParams['order_dir'] = 'DESC';
}
if (strlen($args['ogc:filter']) > 0) $searchParams['ogc:Filter'] = $args['ogc:filter'];
if (!empty($args['filterFields'])) $searchParams['cols'] = $args['filterFields'];// propertyName
if (!empty($args['primaryKey'])) $searchParams['primaryKey'] = $args['primaryKey'];// featureID
if (!empty($args['bbox'])) $searchParams['f_the_geom'] = "BBOX:{$args['bbox']}";
$queryFeatures = $acl->buildQuery($searchParams);
$totalItems = $queryFeatures->getTotal();
$xmlWriter = new XMLWriter();
if (!$xmlWriter) throw new HttpException("Error no XMLWriter", 404);
$xmlWriter->openUri('php://output');
$xmlWriter->setIndent(true);
$xmlWriter->startDocument('1.0','UTF-8');
$xmlWriter->startElement('wfs:FeatureCollection');
$xmlWriter->writeAttribute('xmlns:wfs', 'http://www.opengis.net/wfs/2.0');
$xmlWriter->writeAttribute('xmlns', 'http://www.opengis.net/wfs/2.0');
$xmlWriter->writeAttribute('xmlns:gml', 'http://www.opengis.net/gml');
$xmlWriter->writeAttribute('xmlns:xsi', 'http://www.w3.org/2001/XMLSchema-instance');
// $xmlWriter->writeAttribute('xsi:schemaLocation', "{$wfsNsUri} {$featureTypeUri}");
$xmlWriter->writeAttribute('numberMatched', $totalItems);
$xmlWriter->writeAttribute('numberReturned', 0);
// $xmlWriter->writeAttribute('timeStamp', "TODO: timestamp like '2011-12-09T11:30:16'");
$xmlWriter->endElement();// wfs:FeatureCollection
$xmlWriter->endDocument();
exit;
}
public function getFeatures($args, $simple = true) {
$type = $args['typeName'];
DBG::log("typeName({$args['xsd:type']})");
$acl = $this->getAclFromTypeName($args['xsd:type']);
DBG::log([ 'msg'=>"typeName({$args['xsd:type']}) - acl(".get_class($acl).")", '$acl'=>$acl ]);
$baseNsUri = Api_WfsNs::getBaseWfsUri();
$rootWfsNs = 'p5';
$rootWfsNsUri = "{$baseNsUri}";
$wfsNs = $args['typePrefix'];
$wfsNsUri = "{$baseNsUri}/" . str_replace('__x3A__', '/', ('p5_' === substr($args['typePrefix'], 0, 3) ? substr($args['typePrefix'], 3) : $args['typePrefix']));
$featureTypeUri = $this->getBaseUri() . "?SERVICE=WFS&VERSION=1.0.0&TYPENAME={$args['xsd:type']}&REQUEST=DescribeFeatureType";
DBG::log("ogcFilter(" . strlen($args['ogc:filter']) . "): {$args['ogc:filter']}");
$searchParams = array();
$searchParams['limit'] = $args['limit'];
$searchParams['limitstart'] = $args['offset'];
if (!empty($args['sortBy'])) {
$searchParams['sortBy'] = $args['sortBy'];
} else {
$searchParams['order_by'] = $acl->getPrimaryKeyField();
$searchParams['order_dir'] = 'DESC';
}
if (strlen($args['ogc:filter']) > 0) $searchParams['ogc:Filter'] = $args['ogc:filter'];
if (!empty($args['filterFields'])) $searchParams['cols'] = $args['filterFields'];// PropertyName
if (!empty($args['primaryKey'])) $searchParams['primaryKey'] = $args['primaryKey'];// featureID
if (!empty($args['bbox'])) $searchParams['f_the_geom'] = "BBOX:{$args['bbox']}";
DBG::log($args, 'array', "\$args");
$schemaCache = array();
Lib::loadClass('Api_Wfs_GetFeature');
try {
$searchParams['cols'] = Api_Wfs_GetFeature::convertOgcPropertyListToFeatureQueryCols($schemaCache, $args['filterFields'], $acl); // convert $args['filterFields'] to field list
} catch (Exception $e) {
DBG::log($e);
throw $e;
}
DBG::log($searchParams, 'string', 'getItems - $searchParams');
$queryFeatures = $acl->buildQuery($searchParams);
$items = $queryFeatures->getItems();
DBG::log($items, 'array', 'getItems - $items');
header('Content-type: application/xml; charset=utf-8');
$xmlWriter = new Core_XmlWriter();
$xmlWriter->openUri('php://output');
// $xmlWriter->openMemory();// DBG
$xmlWriter->setIndent(true);
if (!$xmlWriter) throw new HttpException("Error no XMLWriter", 404);
$xmlWriter->startDocument('1.0','UTF-8');
//$xmlWriter->startElementNS('wfs', 'FeatureCollection', 'http://www.opengis.net/wfs');
$xmlWriter->startElement('wfs:FeatureCollection');
// $xmlWriter->writeAttributeNS('xmlns', 'wfs', 'http://www.w3.org/2000/xmlns/', 'http://www.opengis.net/wfs');
$xmlWriter->writeAttribute('xmlns:wfs', 'http://www.opengis.net/wfs');
$xmlWriter->writeAttribute('xmlns', 'http://www.opengis.net/wfs');
$xmlWriter->writeAttribute('xmlns:gml', 'http://www.opengis.net/gml');
$xmlWriter->writeAttribute('xmlns:xsi', 'http://www.w3.org/2001/XMLSchema-instance');
$xmlWriter->writeAttribute('xmlns:xlink', 'http://www.w3.org/1999/xlink');
$xlmns = [];
$xlmns[ $wfsNs ] = $wfsNsUri;
if (!$simple) $xlmns[ $rootWfsNs ] = $rootWfsNsUri;
foreach ($schemaCache as $childSchema) {
$xlmns[ $childSchema['nsPrefix'] ] = "{$rootWfsNsUri}/" . str_replace('__x3A__', '/', $childSchema['nsPrefix']);
}
foreach ($xlmns as $prefixXmlns => $urlXmlns) {
$xmlWriter->writeAttribute("xmlns:{$prefixXmlns}", $urlXmlns);
}
$xmlWriter->writeAttribute('xsi:schemaLocation', "{$wfsNsUri} {$featureTypeUri}"); // TODO: BUG $wfsNsUri
$xmlWriter->writeAttribute('numberMatched', 'unknown'); // TODO: return total items if simple query (without prefix, small total number, maxFeatures set, etc.)
// NOTE: for client: if numberMatched == 'unknown' then request with resultType = 'hits'
$xmlWriter->writeAttribute('numberReturned', count($items));
$tblName = $acl->getName();
$primaryKeyField = $acl->getPrimaryKeyField();
foreach ($items as $item) {
$itemKey = V::get($primaryKeyField, '', $item);
if (!is_array($item)) $item = (array)$item;
if (!empty($geomFld)) DBG::log($item[$geomFld], 'array', "item[{$itemKey}] ({$geomFld})isEmpty(".empty($item[$geomFld])."):");
DBG::log($item, 'array' , ">>> loop({$itemKey})");
DBG::log($searchParams['cols'], 'array' , "\$searchParams['cols']");
$xmlWriter->startElement('gml:featureMember');
Api_Wfs_GetFeature::printXmlFeatureRecurse($xmlWriter, $acl, $item, $searchParams['cols'], $tagName = "{$wfsNs}:{$type}", array_merge(
[
'fid' => "{$type}.{$itemKey}",
],
(!$simple)
? [ "{$rootWfsNs}:web_link" => Request::getPathUri() . "index.php?_route=ViewTableAjax&namespace=" . $acl->getNamespace() . "#EDIT/{$itemKey}" ]
: []
), $showAdvancedAttrs = !$simple, $schemaCache);
$xmlWriter->endElement();// gml:featureMember
}
$xmlWriter->endElement();// wfs:FeatureCollection
$xmlWriter->endDocument();
exit;
}
public function describeFeatureTypeAction() {
$type = V::get('TYPENAME', '', $_REQUEST);
if (empty($type)) {
$reqContent = Request::getRequestBody();
if (!empty($reqContent)) {
return $this->_parseDescribeFeatureTypeRequest($reqContent);
} else {
return $this->_getDescribeFeatureAllTypes();
}
//throw new HttpException("Wrong param TYPENAME", 400);
}
$typeEx = explode(':', $type);
if (count($typeEx) != 2) throw new HttpException("Wrong param TYPENAME", 400);
return $this->_getDescribeFeatureType($typeEx[0], $typeEx[1]);
}
public function describeFeatureTypeAdvancedAction() {
$typeName = V::geti('TYPENAME', '', $_REQUEST);
if (empty($typeName)) {
$reqContent = Request::getRequestBody();
if (!empty($reqContent)) {
return $this->_parseDescribeFeatureTypeRequest($reqContent, $simple = false);
} else {
return $this->_getDescribeFeatureAllTypes($simple = false);
}
//throw new HttpException("Wrong param TYPENAME", 400);
}
if (false === strpos($typeName, ':')) throw new HttpException("Wrong param TYPENAME", 400);
list($nsPrefix, $name) = explode(':', $typeName);
if ('/@instance' == strtolower(substr($name, -1 * strlen('/@instance')))) {
return $this->_describeInstanceAttributeTable($nsPrefix, substr($name, 0, -1 * strlen('/@instance')));
}
return $this->_getDescribeFeatureType($nsPrefix, $name, $simple = false);
}
public function getCapabilitiesAction() {
$wfsServerUrl = $this->getBaseUri();
$serviceTitle = "Web Feature Service";
$serviceDescription = "This is the reference implementation of WFS 1.0.0 and WFS 1.1.0, supports all WFS operations including Transaction.";
$idDefaultDB = DB::getPDO()->getZasobId();
$aclList = array_filter($this->_usrAcl->getTablesAcl(), function ($acl) use ($idDefaultDB) {
// // $dataSourceName = 'default_db';// TODO: getSourceName
// // $tblName = $tblAcl->getName();
// // try {
// // $acl = $this->getAclFromTypeName($typeName = "p5_{$dataSourceName}:{$tblName}");
// // } catch (Exception $e) {
// // // echo "Error for table({$tblName}): " . $e->getMessage() . "\n";
// // }
// // if (!$acl) {
// // // TODO: error log msg
// // return false;
// // }
return ($idDefaultDB == $acl->getDB()); // hide non default_db tables
});
switch (V::get('outputFormat', 'xml', $_GET)) {
case 'csv': {
(new Api_Wfs_GetCapabilities)->getCapabilitiesCsv($wfsServerUrl, $serviceTitle, $serviceDescription, $aclList);
} break;
case 'xml': {
(new Api_Wfs_GetCapabilities)->getCapabilitiesXml($wfsServerUrl, $serviceTitle, $serviceDescription, $aclList);
} break;
default: throw new Api_WfsException("Not Implemented outputFormat", 501); // , null, 'NotImplemented', 'request');
}
exit;
}
}