|
|
@@ -0,0 +1,288 @@
|
|
|
+<?php
|
|
|
+
|
|
|
+Lib::loadClass('Api_WfsServerBase');
|
|
|
+Lib::loadClass('Api_WfsException');
|
|
|
+Lib::loadClass('Api_WfsGeomTypeConverter');
|
|
|
+
|
|
|
+class Api_WfsQgisServer extends Api_WfsServerBase {
|
|
|
+
|
|
|
+ public function parseXMLRequest() {
|
|
|
+ $data = array();
|
|
|
+ $reqContent = file_get_contents('php://input');
|
|
|
+ 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("TODO ... L." . __LINE__, 501);
|
|
|
+
|
|
|
+ $xml = new SimpleXMLElement($reqContent);
|
|
|
+ $namespaces = $xml->getNameSpaces(true);
|
|
|
+
|
|
|
+ if ('Transaction' == $xml->getName()) {
|
|
|
+ $this->_parseTransactionXml($xml);
|
|
|
+ }
|
|
|
+ else {
|
|
|
+ throw new Api_WfsException("Not Implemented " . htmlspecialchars($xml->getName()), 501);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ public function getFeatureAction() {
|
|
|
+ $type = V::get('TYPENAME', '', $_REQUEST);
|
|
|
+ $typeEx = explode(':', $type);
|
|
|
+ $maxFeatures = V::get('MAXFEATURES', '10000', $_REQUEST, 'int');// TODO: Set Deafult Limit
|
|
|
+ $srsname = V::get('SRSNAME', '', $_REQUEST);// eg. EPSG:4326
|
|
|
+ if (count($typeEx) == 2) {
|
|
|
+ return $this->getFeatures($typeEx[0], $typeEx[1], $maxFeatures, $srsname);
|
|
|
+ } else {
|
|
|
+ throw new HttpException("Wrong param TYPENAME", 400);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ public function getFeatures($nsPrefix, $type, $maxFeatures, $srsname) {
|
|
|
+ $DBG = (V::get('DBG_GEO', '', $_GET) > 0);// TODO: Profiler
|
|
|
+ $typeName = "{$nsPrefix}:{$type}";
|
|
|
+ $acl = $this->getAclFromTypeName($typeName);
|
|
|
+ $fldList = $acl->getRealFieldList();
|
|
|
+
|
|
|
+ $baseNsUri = $this->getBaseNamespaceUri();
|
|
|
+ $wfsNs = 'p5_default_db_' . $type;//$nsPrefix;
|
|
|
+ $wfsNsUri = "{$baseNsUri}/" . substr($nsPrefix, 3) . '/' . $type;
|
|
|
+
|
|
|
+ // get BBox from geom_field (only one geom fld is allowed)
|
|
|
+ $geomFld = null;
|
|
|
+ {
|
|
|
+ foreach ($fldList as $fldName) {
|
|
|
+ if ($acl->isGeomField($fldName)) {
|
|
|
+ $geomFld = $fldName;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ $dbGeomType = $acl->getGeomFieldType($geomFld);
|
|
|
+
|
|
|
+ $searchParams = array();
|
|
|
+ $searchParams['limit'] = $maxFeatures;
|
|
|
+ $searchParams['order_by'] = $acl->getPrimaryKeyField();
|
|
|
+ $searchParams['order_dir'] = 'DESC';
|
|
|
+ if ($geomFld) $searchParams["f_{$geomFld}"] = 'IS NOT NULL';
|
|
|
+ if ($geomFld) $searchParams["f_{$geomFld}"] = 'GeometryType=' . strtoupper($dbGeomType);
|
|
|
+ //if ($geomFld) $searchParams["f_{$geomFld}"] = 'GeometryType=LINESTRING';
|
|
|
+if($DBG){echo 'getItems:';print_r($searchParams);echo "\n";}
|
|
|
+ $items = $acl->getItems($searchParams);
|
|
|
+
|
|
|
+ $dom = new DOMDocument('1.0', 'utf-8');
|
|
|
+ $dom->formatOutput = true;
|
|
|
+ $dom->preserveWhiteSpace = false;
|
|
|
+ $rootNode = $dom->createElementNS('http://www.opengis.net/wfs', 'wfs:FeatureCollection');
|
|
|
+ $dom->appendChild($rootNode);
|
|
|
+ $rootNode->setAttributeNS('http://www.w3.org/2000/xmlns/', 'xmlns', 'http://www.opengis.net/wfs');
|
|
|
+ $rootNode->setAttributeNS('http://www.w3.org/2000/xmlns/', 'xmlns:wfs', 'http://www.opengis.net/wfs');
|
|
|
+ $rootNode->setAttributeNS('http://www.w3.org/2000/xmlns/', 'xmlns:gml', 'http://www.opengis.net/gml');
|
|
|
+ $rootNode->setAttributeNS('http://www.w3.org/2000/xmlns/', 'xmlns:xsi', 'http://www.w3.org/2001/XMLSchema-instance');
|
|
|
+ $rootNode->setAttributeNS('http://www.w3.org/2000/xmlns/', 'xmlns:' . $wfsNs, $wfsNsUri);
|
|
|
+ $rootNode->setAttribute('xsi:schemaLocation', 'http://www.opengis.net/wfs');// TODO: add DescribeFeatureType xsd uri
|
|
|
+
|
|
|
+if(0){// TODO: get BBOX for add features
|
|
|
+ $boundedByNode = $dom->createElementNS('http://www.opengis.net/gml', 'gml:boundedBy');
|
|
|
+ $rootNode->appendChild($boundedByNode);
|
|
|
+ $boxNode = $dom->createElementNS('http://www.opengis.net/gml', 'gml:Box');
|
|
|
+ $boundedByNode->appendChild($boxNode);
|
|
|
+ $boxNode->setAttribute('srsName', "http://www.opengis.net/gml/srs/epsg.xml#4326");// TODO: EPSG
|
|
|
+ $coordinatesNode = $dom->createElementNS('http://www.opengis.net/gml', 'gml:coordinates');
|
|
|
+ $boxNode->appendChild($coordinatesNode);
|
|
|
+ $coordinatesNode->setAttributeNS('http://www.w3.org/2000/xmlns/', 'xmlns:gml', 'http://www.opengis.net/gml');
|
|
|
+ $coordinatesNode->setAttribute('decimal', '.');
|
|
|
+ $coordinatesNode->setAttribute('cs', ',');
|
|
|
+ $coordinatesNode->setAttribute('ts', ' ');
|
|
|
+ $coordinatesNode->nodeValue = '1544947.6295,4322758.105 1548002.2259,4330464.1001';// TODO: coordinates for all items?
|
|
|
+}
|
|
|
+
|
|
|
+if($DBG){echo '(geomFld: '.$geomFld.'):';print_r($acl->getFieldType($geomFld));echo "\n";}
|
|
|
+ if (empty($items)) {
|
|
|
+ $pKeyField = $acl->getPrimaryKeyField();
|
|
|
+ $fakeItem = new stdClass();
|
|
|
+ $fakeItem->{$pKeyField} = 0;
|
|
|
+ if ('polygon' == $dbGeomType) {
|
|
|
+ $fakeItem->the_geom = "POLYGON(())";
|
|
|
+ } else if ('linestring' == $dbGeomType) {
|
|
|
+ $fakeItem->the_geom = "LINESTRING()";
|
|
|
+ } else if ('point' == $dbGeomType) {
|
|
|
+ $fakeItem->the_geom = "POINT(0,0)";
|
|
|
+ }
|
|
|
+ $items[0] = $fakeItem;
|
|
|
+ }
|
|
|
+ foreach ($items as $itemKey => $item) {
|
|
|
+ //if($item->ID == 19)continue;
|
|
|
+
|
|
|
+if($DBG){echo 'item['.$itemKey.'] ('.$geomFld.')isEmpty('.empty($item->{$geomFld}).'):';print_r($item->{$geomFld});echo "\n";}
|
|
|
+ if ($geomFld) {
|
|
|
+ if (empty($item->{$geomFld})) {
|
|
|
+ continue;// QGIS crash when WFS contain features with empty geom field
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ $featureMemberNode = $dom->createElementNS('http://www.opengis.net/gml', 'gml:featureMember');
|
|
|
+ $rootNode->appendChild($featureMemberNode);
|
|
|
+ $featureNode = $dom->createElementNS($wfsNsUri, "{$wfsNs}:{$type}");
|
|
|
+ $featureMemberNode->appendChild($featureNode);
|
|
|
+ $featureNode->setAttribute('fid', "{$type}.{$itemKey}");
|
|
|
+if(0){// TODO: get BBOX
|
|
|
+ $boundedByNode = $dom->createElementNS('http://www.opengis.net/gml', 'gml:boundedBy');
|
|
|
+ $featureNode->appendChild($boundedByNode);
|
|
|
+ $boxNode = $dom->createElementNS('http://www.opengis.net/gml', 'gml:Box');
|
|
|
+ $boundedByNode->appendChild($boxNode);
|
|
|
+ $boxNode->setAttribute('srsName', "http://www.opengis.net/gml/srs/epsg.xml#4326");// TODO: EPSG
|
|
|
+ $coordinatesNode = $dom->createElementNS('http://www.opengis.net/gml', 'gml:coordinates');
|
|
|
+ $boxNode->appendChild($coordinatesNode);
|
|
|
+ $coordinatesNode->setAttributeNS('http://www.w3.org/2000/xmlns/', 'xmlns:gml', 'http://www.opengis.net/gml');
|
|
|
+ $coordinatesNode->setAttribute('decimal', '.');
|
|
|
+ $coordinatesNode->setAttribute('cs', ',');
|
|
|
+ $coordinatesNode->setAttribute('ts', ' ');
|
|
|
+ $coordinatesNode->nodeValue = '1546472.2363,4328949.5775 1548002.2259,4330464.1001';// TODO: coordinates for item?
|
|
|
+}
|
|
|
+ foreach ($fldList as $fldName) {
|
|
|
+ $featureFldNode = $dom->createElementNS($wfsNsUri, "{$wfsNs}:{$fldName}");
|
|
|
+ if ($acl->isGeomField($fldName)) {
|
|
|
+ $geomNode = $this->_typeConverter->createGmlFromWkt($item->{$fldName}, $dom);
|
|
|
+ if (!$geomNode) continue;
|
|
|
+ $featureFldNode->appendChild($geomNode);
|
|
|
+ } else {
|
|
|
+ $featureFldNode->nodeValue = str_replace('&', '&', $item->{$fldName});
|
|
|
+ if (empty($featureFldNode->nodeValue)) {
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ $featureNode->appendChild($featureFldNode);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ return $dom->saveXml();
|
|
|
+ }
|
|
|
+
|
|
|
+ public function describeFeatureTypeAction() {
|
|
|
+ $type = V::get('TYPENAME', '', $_REQUEST);
|
|
|
+ if (empty($type)) {
|
|
|
+ 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 getDescribeFeatureType($nsPrefix, $type) {
|
|
|
+ $typeName = "{$nsPrefix}:{$type}";
|
|
|
+ $acl = $this->getAclFromTypeName($typeName);
|
|
|
+
|
|
|
+ $baseNsUri = $this->getBaseNamespaceUri();
|
|
|
+ $wfsNs = 'p5_default_db_' . $type;//$nsPrefix;
|
|
|
+ $wfsNsUri = "{$baseNsUri}/" . substr($nsPrefix, 3) . '/' . $type;
|
|
|
+
|
|
|
+ if (empty($type)) {
|
|
|
+ throw new HttpException("Feature Type Name not defined", 400);
|
|
|
+ }
|
|
|
+ if (!$this->isAllowedFeatureType($nsPrefix, $type)) {
|
|
|
+ throw new Api_WfsException("Could not find type: " . htmlspecialchars($type));
|
|
|
+ }
|
|
|
+
|
|
|
+ $typeName = $type . 'Type';
|
|
|
+ $fldList = $acl->getRealFieldList();
|
|
|
+ header('Content-type: application/xml');
|
|
|
+ // <xsd:import namespace="http://www.opengis.net/gml" schemaLocation="http://webgis.regione.sardegna.it:80/geoserver/schemas/gml/2.1.2/feature.xsd"/>
|
|
|
+ // <xsd:element name="{type}" substitutionGroup="gml:_Feature" type="dbu:{typeName}"/>
|
|
|
+
|
|
|
+ $dom = new DOMDocument('1.0', 'utf-8');
|
|
|
+ $dom->formatOutput = true;
|
|
|
+ $dom->preserveWhiteSpace = false;
|
|
|
+ $rootNode = $dom->createElementNS('http://www.w3.org/2001/XMLSchema', 'xsd:schema');
|
|
|
+ $dom->appendChild($rootNode);
|
|
|
+ $rootNode->setAttributeNS('http://www.w3.org/2000/xmlns/', 'xmlns:gml', 'http://www.opengis.net/gml');
|
|
|
+ $rootNode->setAttributeNS('http://www.w3.org/2000/xmlns/', 'xmlns:' . $wfsNs, $wfsNsUri);
|
|
|
+ $rootNode->setAttribute('elementFormDefault', 'qualified');
|
|
|
+ $rootNode->setAttribute('targetNamespace', $wfsNsUri);
|
|
|
+
|
|
|
+ $cTypeNode = $dom->createElementNS('http://www.w3.org/2001/XMLSchema', 'xsd:complexType');
|
|
|
+ $rootNode->appendChild($cTypeNode);
|
|
|
+ $cTypeNode->setAttribute('name', $typeName);
|
|
|
+
|
|
|
+ $cConNode = $dom->createElementNS('http://www.w3.org/2001/XMLSchema', 'xsd:complexContent');
|
|
|
+ $cTypeNode->appendChild($cConNode);
|
|
|
+
|
|
|
+ $extNode = $dom->createElementNS('http://www.w3.org/2001/XMLSchema', 'xsd:extension');
|
|
|
+ $cConNode->appendChild($extNode);
|
|
|
+ $extNode->setAttribute('base', 'gml:AbstractFeatureType');
|
|
|
+
|
|
|
+ $seqNode = $dom->createElementNS('http://www.w3.org/2001/XMLSchema', 'xsd:sequence');
|
|
|
+ $extNode->appendChild($seqNode);
|
|
|
+
|
|
|
+ // <xsd:element maxOccurs="1" minOccurs="0" name="{$fldName}" nillable="true" type="xsd:integer"/>
|
|
|
+ $pKeyField = $acl->getPrimaryKeyField();
|
|
|
+ foreach ($fldList as $fldName) {
|
|
|
+ $elNode = $dom->createElementNS('http://www.w3.org/2001/XMLSchema', 'xsd:element');
|
|
|
+ $seqNode->appendChild($elNode);
|
|
|
+ $elNode->setAttribute('name', $fldName);
|
|
|
+ $minOccurs = 0;
|
|
|
+ if ($pKeyField == $fldName) {
|
|
|
+ $minOccurs = '1';
|
|
|
+ } else {
|
|
|
+ $minOccurs = '0';
|
|
|
+ }
|
|
|
+ $elNode->setAttribute('minOccurs', $minOccurs);
|
|
|
+ if ($acl->isIntegerField($fldName)) {
|
|
|
+ $fldType = 'xsd:integer';
|
|
|
+ }
|
|
|
+ else if ($acl->isDecimalField($fldName)) {
|
|
|
+ $fldType = 'xsd:decimal';
|
|
|
+ }
|
|
|
+ else if ($acl->isDateField($fldName)) {
|
|
|
+ $fldType = 'xsd:date';
|
|
|
+ }
|
|
|
+ else if ($acl->isDateTimeField($fldName)) {
|
|
|
+ $fldType = 'xsd:dateTime';
|
|
|
+ }
|
|
|
+ else if ($acl->isGeomField($fldName)) {
|
|
|
+ $fldType = 'gml:GeometryPropertyType';
|
|
|
+ //$fldType = 'gml:Polygon';// nie działa musi być gml:GeometryPropertyType
|
|
|
+ }
|
|
|
+ else {
|
|
|
+ $fldType = 'xsd:string';
|
|
|
+ }
|
|
|
+ $elNode->setAttribute('type', $fldType);
|
|
|
+ $elNode->setAttribute('nillable', 'true');
|
|
|
+ }
|
|
|
+
|
|
|
+ $elNode = $dom->createElementNS('http://www.w3.org/2001/XMLSchema', 'xsd:element');
|
|
|
+ $rootNode->appendChild($elNode);
|
|
|
+ $elNode->setAttribute('name', $type);
|
|
|
+ $elNode->setAttribute('type', $wfsNs . ':' . $typeName);
|
|
|
+
|
|
|
+ echo $dom->saveXML();
|
|
|
+ }
|
|
|
+
|
|
|
+ public function getCapabilitiesAction() {
|
|
|
+ $wfsServerUrl = $this->getBaseUri();
|
|
|
+ $serviceTitle = "Web Feature Service for QGIS";
|
|
|
+ $serviceDescription = "This is the reference implementation of WFS 1.0.0 and WFS 1.1.0, supports all WFS operations including Transaction.";
|
|
|
+
|
|
|
+ //header('Content-type: application/xml; charset="utf-8"');
|
|
|
+ header('Content-type: application/xml');
|
|
|
+ $this->_getCapabilities($wfsServerUrl, $serviceTitle, $serviceDescription);
|
|
|
+ }
|
|
|
+
|
|
|
+}
|