|
|
@@ -5,7 +5,7 @@ Lib::loadClass('Api_WfsGeomTypeConverter');
|
|
|
Lib::loadClass('Api_WfsNs');
|
|
|
Lib::loadClass('Request');
|
|
|
Lib::loadClass('Core_AclHelper');
|
|
|
-Lib::loadClass('Core_XMLWriter');
|
|
|
+Lib::loadClass('Core_XmlWriter');
|
|
|
|
|
|
class Api_WfsServerBase {
|
|
|
|
|
|
@@ -52,6 +52,29 @@ class Api_WfsServerBase {
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+ try { // TODO: use object cache `CRM_#CACHE_ACL_OBJECT`
|
|
|
+ $namespace = str_replace([':', '__x3A__'], '/', $typeName);
|
|
|
+ Lib::loadClass('SchemaFactory');
|
|
|
+ $objItem = SchemaFactory::loadDefaultObject('SystemObject')->getItem($namespace, ['propertyName'=>"*,field"]);
|
|
|
+ DBG::log($objItem, 'array', "DBG objItem({$namespace})");
|
|
|
+ if (!$objItem['idZasob']) throw new Exception("Missing idZasob for namespace '{$namespace}'");
|
|
|
+ if (!in_array($objItem['_type'], [
|
|
|
+ // 'TableAcl', // TODO: TEST - to replace TableAcl by AntAcl or use object with namespace + '/tableName'?
|
|
|
+ 'AntAcl',
|
|
|
+ ])) throw new Exception("Not Implemented acl type '{$objItem['_type']}'");
|
|
|
+ if (!$objItem['isObjectActive']) {
|
|
|
+ if (!$objItem['hasStruct']) throw new Exception("namespace has no structure '{$namespace}'");
|
|
|
+ if (!$objItem['isStructInstalled']) throw new Exception("namespace structure not installed '{$namespace}'");
|
|
|
+ throw new Exception("namespace is not activated '{$namespace}'");
|
|
|
+ }
|
|
|
+
|
|
|
+ Lib::loadClass('AntAclBase');
|
|
|
+ $acl = AntAclBase::buildInstance($objItem['idZasob'], $objItem);
|
|
|
+ return $acl;
|
|
|
+ } catch (Exception $e) {
|
|
|
+ DBG::log($e);
|
|
|
+ }
|
|
|
+
|
|
|
$typeEx = explode(':', $typeName);
|
|
|
$sourceName = $typeEx[0];
|
|
|
$objName = $typeEx[1];
|
|
|
@@ -107,8 +130,14 @@ class Api_WfsServerBase {
|
|
|
if (empty($args['ogc:filter'])) {// read ogc:Filter from POST body if not defined in GET
|
|
|
$reqBody = Request::getRequestBody();
|
|
|
if (!empty($reqBody)) {
|
|
|
- $args['ogc:filter'] = $this->convertOgcFilterFromRequestBody($reqBody);
|
|
|
- if (empty($args['ogc:filter'])) throw new Api_WfsException("Error Processing ogc:Filter", 501);
|
|
|
+ $parsedRequest = $this->parseOgcFilterRequest($reqBody);
|
|
|
+ DBG::log($parsedRequest, 'array', 'parsed ogc query request');
|
|
|
+ if (!empty($parsedRequest['ogc:Filter'])) $args['ogc:filter'] = $parsedRequest['ogc:Filter'];
|
|
|
+ if (!empty($parsedRequest['wfs:PropertyName'])) {
|
|
|
+ foreach ($parsedRequest['wfs:PropertyName'] as $fieldXpath) {
|
|
|
+ $args['filterFields'][] = $fieldXpath;
|
|
|
+ }
|
|
|
+ }
|
|
|
}
|
|
|
}
|
|
|
|
|
|
@@ -116,7 +145,6 @@ class Api_WfsServerBase {
|
|
|
|
|
|
$args['wfs:propertyName'] = trim(V::get('propertyname', '', $lowerArgs));// TODO: fields to show - split by ','
|
|
|
if (strlen($args['wfs:propertyName']) > 0) {
|
|
|
- $args['filterFields'] = array();
|
|
|
$exFields = explode(',', $args['wfs:propertyName']);
|
|
|
foreach ($exFields as $fieldName) {
|
|
|
$fieldName = trim($fieldName);
|
|
|
@@ -169,11 +197,11 @@ class Api_WfsServerBase {
|
|
|
public function _getCapabilities($wfsServerUrl, $serviceTitle, $serviceDescription) {
|
|
|
if (V::get('DBG_ACL', '', $_GET)) {
|
|
|
{
|
|
|
- echo "Core_AclHelper::getAclList = [" . "\n";
|
|
|
- foreach (Core_AclHelper::getAclList() as $typeName) {
|
|
|
+ echo "Core_AclHelper::getCustomAclList = [" . "\n";
|
|
|
+ foreach (Core_AclHelper::getCustomAclList() as $typeName) {
|
|
|
echo "|\t{$typeName}" . "\n";
|
|
|
}
|
|
|
- echo "]// .EOF Core_AclHelper::getAclList" . "\n";
|
|
|
+ echo "]// .EOF Core_AclHelper::getCustomAclList" . "\n";
|
|
|
}
|
|
|
|
|
|
$fullTblAclList = $this->_usrAcl->getTablesAcl();
|
|
|
@@ -181,7 +209,7 @@ class Api_WfsServerBase {
|
|
|
die("\n" . '.EOF - DBG_ACL');
|
|
|
}
|
|
|
header('Content-type: application/xml; charset=utf-8');
|
|
|
- $xmlWriter = new Core_XMLWriter();
|
|
|
+ $xmlWriter = new Core_XmlWriter();
|
|
|
if (!$xmlWriter) throw new HttpException("Error no XMLWriter", 404);
|
|
|
$xmlWriter->openUri('php://output');
|
|
|
$xmlWriter->setIndent(true);
|
|
|
@@ -299,10 +327,12 @@ class Api_WfsServerBase {
|
|
|
|
|
|
$featureTypeNodes = [];
|
|
|
foreach ($this->_getTableAclList() as $tblAcl) {
|
|
|
+ $ns = Core_AclHelper::parseNamespaceUrl($tblAcl->getNamespace());
|
|
|
+ DBG::log(['ns'=>$ns, 'acl_ns'=>$tblAcl->getNamespace(), 'cls'=>get_class($tblAcl)], 'array', "tblAcl [".$tblAcl->getID()."]");
|
|
|
$dataSourceName = 'default_db';// TODO: $tblAcl->getSourceName()
|
|
|
$prefix = "p5_{$dataSourceName}";
|
|
|
$featureTypeNodes[] = [ 'FeatureType', [ "xmlns:{$prefix}" => Api_WfsNs::getNsUri($prefix) ], [
|
|
|
- [ 'Name', $prefix . ':' . $tblAcl->getName() ],
|
|
|
+ [ 'Name', "p5_" . "{$ns['prefix']}:{$ns['name']}" ], // TODO: remove 'p5_' prefix
|
|
|
[ 'Title', $tblAcl->getRawLabel() ],
|
|
|
[ 'Abstract', $tblAcl->getRawOpis() ],
|
|
|
[ 'Keywords', implode(', ', [ $tblAcl->getID(), $tblAcl->getName(), $tblAcl->getRawLabel() ]) ],
|
|
|
@@ -312,20 +342,25 @@ class Api_WfsServerBase {
|
|
|
'miny' => "38.8575126897477",
|
|
|
'maxx' => "9.838674658246807",
|
|
|
'maxy' => "41.31378404137082"], null ]
|
|
|
- ]];
|
|
|
+ ] ];
|
|
|
}
|
|
|
- foreach (Core_AclHelper::getAclList() as $typeName) {
|
|
|
+ foreach (Core_AclHelper::getCustomAclList() as $typeName) {
|
|
|
list($prefix, $name) = explode(':', $typeName);
|
|
|
$featureTypeNodes[] = [ 'FeatureType', [ "xmlns:{$prefix}" => Api_WfsNs::getNsUri($prefix) ], [
|
|
|
- [ 'Name', $name ],
|
|
|
+ [ 'Name', "{$prefix}:{$name}" ],
|
|
|
[ 'Title', $name ],
|
|
|
[ 'Abstract', $name ],
|
|
|
[ 'Keywords', $name ],
|
|
|
[ 'SRS', 'EPSG:4326' ],
|
|
|
- ]];
|
|
|
+ ] ];
|
|
|
}
|
|
|
$xmlWriter->startElement('FeatureTypeList');
|
|
|
$xmlWriter->h('Operations', ['Query', 'Insert', 'Update', 'Delete', 'Lock']);
|
|
|
+ if (DBG::isActive()) {
|
|
|
+ DBG::log(array_map(function ($feature) {
|
|
|
+ return "{$feature[2][0][1]}, ".array_values($feature[1])[0];
|
|
|
+ }, $featureTypeNodes), 'array', "\$featureTypeNodes");
|
|
|
+ }
|
|
|
foreach ($featureTypeNodes as $node) {
|
|
|
$xmlWriter->h($node);
|
|
|
}
|
|
|
@@ -1263,7 +1298,7 @@ if($DBG){echo 'L.' . __LINE__ . ' $validateConvertedTransactionXsdString:';print
|
|
|
$featureTypeUri = $this->getBaseUri() . "?SERVICE=WFS&VERSION=1.0.0&TYPENAME={$args['xsd:type']}&REQUEST=DescribeFeatureType";
|
|
|
|
|
|
header('Content-type: application/xml; charset=utf-8');
|
|
|
- $xmlWriter = new Core_XMLWriter();
|
|
|
+ $xmlWriter = new Core_XmlWriter();
|
|
|
if (!$xmlWriter) throw new HttpException("Error no XMLWriter", 404);
|
|
|
$xmlWriter->openUri('php://output');
|
|
|
$xmlWriter->setIndent(true);
|
|
|
@@ -1290,7 +1325,7 @@ if($DBG){echo 'L.' . __LINE__ . ' $validateConvertedTransactionXsdString:';print
|
|
|
$acl = $this->getAclFromTypeName("{$nsPrefix}:{$name}");
|
|
|
|
|
|
header('Content-type: application/xml; charset=utf-8');
|
|
|
- $xmlWriter = new Core_XMLWriter();
|
|
|
+ $xmlWriter = new Core_XmlWriter();
|
|
|
if (!$xmlWriter) throw new HttpException("Error no XMLWriter", 404);
|
|
|
$xmlWriter->openUri('php://output');
|
|
|
$xmlWriter->setIndent(true);
|
|
|
@@ -1414,7 +1449,7 @@ if($DBG){echo 'L.' . __LINE__ . ' $validateConvertedTransactionXsdString:';print
|
|
|
if (!array_key_exists($aclNamespaceUri, $nsMap)) $nsMap[$aclNamespaceUri] = $acl->getSourceName();
|
|
|
}
|
|
|
|
|
|
- $xmlWriter = new Core_XMLWriter();
|
|
|
+ $xmlWriter = new Core_XmlWriter();
|
|
|
if (!$xmlWriter) throw new HttpException("Error no XMLWriter", 404);
|
|
|
$xmlWriter->openMemory();// openUri('php://output');
|
|
|
$xmlWriter->setIndent(true);
|
|
|
@@ -1677,15 +1712,15 @@ if($DBG){echo 'L.' . __LINE__ . ' $validateConvertedTransactionXsdString:';print
|
|
|
if ($idDefaultDB != $tblAcl->getDB()) {// hide non default_db tables
|
|
|
continue;
|
|
|
}
|
|
|
- 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
|
|
|
- continue;
|
|
|
- }
|
|
|
+ // 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
|
|
|
+ // continue;
|
|
|
+ // }
|
|
|
$tblAclList[] = $tblAcl;
|
|
|
}
|
|
|
return $tblAclList;
|
|
|
@@ -1705,38 +1740,71 @@ if($DBG){echo 'L.' . __LINE__ . ' $validateConvertedTransactionXsdString:';print
|
|
|
$this->_logger->DBG($reqLog, $lineNr, $funName, $className);
|
|
|
}
|
|
|
|
|
|
- public function convertOgcFilterFromRequestBody($requestOgcFilter) {
|
|
|
- $ogcFilter = '';
|
|
|
- if (empty($requestOgcFilter)) return '';
|
|
|
- {
|
|
|
- $convertOgcFilterXslString .= <<<EOF
|
|
|
-<xsl:transform version="1.0"
|
|
|
- xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
|
|
|
- xmlns:wfs="http://www.opengis.net/wfs"
|
|
|
- xmlns:ogc="http://www.opengis.net/ogc"
|
|
|
- xmlns:gml="http://www.opengis.net/gml">
|
|
|
- <xsl:output method="xml" omit-xml-declaration="yes" indent="yes"/>
|
|
|
- <xsl:template match="/">
|
|
|
- <xsl:for-each select="//*[local-name() = 'GetFeature']">
|
|
|
- <xsl:copy-of select="ogc:Filter"/>
|
|
|
- </xsl:for-each>
|
|
|
- </xsl:template>
|
|
|
-</xsl:transform>
|
|
|
-EOF;
|
|
|
+ public function parseOgcFilterRequest($requestOgcFilter) {
|
|
|
+ // GetFeature: @maxFeatures, @traverseXlinkDepth, @traverseXlinkExpiry
|
|
|
+ // \-- (1..) wfs:Query: @typeName
|
|
|
+ // \--- (0..) ---: wfs:PropertyName
|
|
|
+ // : wfs:XlinkPropertyName
|
|
|
+ // : ogc:Function
|
|
|
+ // ogc:Filter
|
|
|
+ // ogc:SortBy
|
|
|
+ // \--- (1..) ogc:SortProperty
|
|
|
+ // \---: ogc:PropertyName
|
|
|
+ // : ogc:SortOrder ( DESC / ASC )
|
|
|
+ // <ogc:SortBy>
|
|
|
+ // <ogc:SortProperty>
|
|
|
+ // <ogc:PropertyName>ASTA</ogc:PropertyName>
|
|
|
+ // <ogc:SortOrder>ASC</ogc:SortOrder>
|
|
|
+ // </ogc:SortProperty>
|
|
|
+ // </ogc:SortBy>
|
|
|
|
|
|
- DBG::_('DBG_XML', '>2', "convertOgcFilterXslString", $convertOgcFilterXslString, __CLASS__, __FUNCTION__, __LINE__);
|
|
|
- $convertTransactionXsl = new DOMDocument();
|
|
|
- $convertTransactionXsl->loadXml($convertOgcFilterXslString);
|
|
|
+ if (empty($requestOgcFilter)) return '';
|
|
|
+ $requestXml = new DOMDocument();
|
|
|
+ $requestXml->loadXml($requestOgcFilter);
|
|
|
+ $nodesQuery = [];
|
|
|
+ foreach ($requestXml->getElementsByTagNameNS('http://www.opengis.net/wfs', 'Query') as $element) {
|
|
|
+ DBG::log($element->nodeName, 'array', "main loop - wfs:Query");
|
|
|
+ $nodesQuery[] = $element;
|
|
|
+ }
|
|
|
|
|
|
- $requestXml = new DOMDocument();
|
|
|
- $requestXml->loadXml($requestOgcFilter);
|
|
|
+ if (empty($nodesQuery)) { // legacy - try to find 'ogc:Filter'
|
|
|
+ $tagsFilter = [];
|
|
|
+ foreach ($requestXml->getElementsByTagNameNS('http://www.opengis.net/ogc', 'Filter') as $element) {
|
|
|
+ DBG::log($element->nodeName, 'array', "loop element (0 * wfs:Query)");
|
|
|
+ $tagsFilter[] = $requestXml->saveXML($element);
|
|
|
+ }
|
|
|
+ DBG::log($tagsFilter, 'array', "\$tagsFilter (0 * wfs:Query)");
|
|
|
+ return [
|
|
|
+ 'ogc:Filter' => (!empty($tagsFilter))
|
|
|
+ ? reset($tagsFilter) // TODO: only one ogc:Filter allowed
|
|
|
+ : ''
|
|
|
+ ];
|
|
|
+ }
|
|
|
|
|
|
- $proc = new XSLTProcessor();
|
|
|
- $proc->importStylesheet($convertTransactionXsl);
|
|
|
- $ogcFilter = $proc->transformToXML($requestXml);
|
|
|
- DBG::_('DBG_XML', '>2', "ogcFilter", $ogcFilter, __CLASS__, __FUNCTION__, __LINE__);
|
|
|
+ if (1 === count($nodesQuery)) {
|
|
|
+ $tagsFilter = [];
|
|
|
+ foreach ($requestXml->getElementsByTagNameNS('http://www.opengis.net/ogc', 'Filter') as $element) {
|
|
|
+ // DBG::log($element->nodeName, 'array', "loop ogc:Filter (1 * wfs:Query)");
|
|
|
+ $tagsFilter[] = $requestXml->saveXML($element);
|
|
|
+ }
|
|
|
+ DBG::log($tagsFilter, 'array', "\$tagsFilter (1 * wfs:Query)");
|
|
|
+ $tagsWfsPropertyName = [];
|
|
|
+ foreach ($requestXml->getElementsByTagNameNS('http://www.opengis.net/wfs', 'PropertyName') as $element) {
|
|
|
+ // DBG::log($element->nodeValue, 'array', "loop wfs:PropertyName (1 * wfs:Query)");
|
|
|
+ $tagsWfsPropertyName[] = $element->nodeValue;
|
|
|
+ }
|
|
|
+ DBG::log($tagsWfsPropertyName, 'array', "\$tagsWfsPropertyName (1 * wfs:Query)");
|
|
|
+ return array_filter([
|
|
|
+ 'ogc:Filter' => (!empty($tagsFilter))
|
|
|
+ ? reset($tagsFilter)
|
|
|
+ : '',
|
|
|
+ 'wfs:PropertyName' => (!empty($tagsWfsPropertyName))
|
|
|
+ ? $tagsWfsPropertyName
|
|
|
+ : '',
|
|
|
+ ], function ($value) { return !empty($value); });
|
|
|
}
|
|
|
- return $ogcFilter;
|
|
|
+
|
|
|
+ throw new Exception("Not imeplemented multiple ogc:Query"); // multiple ogc:Query require ogc:Query/@typeName
|
|
|
}
|
|
|
|
|
|
}
|