Parcourir la source

added test wps server

Piotr Labudda il y a 8 ans
Parent
commit
ea38d7f390

+ 85 - 0
SE/se-lib/Api/Wps.php

@@ -0,0 +1,85 @@
+<?php
+
+Lib::loadClass('ApiRouteBase');
+Lib::loadClass('Api_WfsException');
+Lib::loadClass('Api_WpsV1_Server');
+Lib::loadClass('UserAcl');
+Lib::loadClass('Api_WfsLogger');
+Lib::loadClass('Api_WsdlServer');
+Lib::loadClass('Type_ApiRequest');
+
+class Api_Wps extends ApiRouteBase {// TODO: extends Api_WfsBase which extends ApiBase
+
+	public $_apiUser;
+	public $_apiBaseUri;
+
+	public function execute(Type_ApiRequest $request) {
+		$wfsLogger = new Api_WfsLogger();
+		$this->setLogger($wfsLogger);
+		$this->reqDBG($request);
+
+		// /wfs-data.php/default_db/?...                    : $request->segments = ['default_db']
+		// /wfs-data.php/filtr_proces_5040/default_db/?...  : $request->segments = ['filtr_proces_5040', 'default_db']
+		// /wfs-data.php?...                                : $request->segments = []
+		// /wfs-data.php/filtr_proces_5040/?...             : $request->segments = ['filtr_proces_5040']
+		// /wfs-data.php/wsdl                               : $request->segments = ['wsdl']
+
+		$serverClass = '';
+		$version = V::get('version', '1.0.0', $request);
+		switch ($version) {
+			case '1.0.0': $serverClass = 'Api_WpsV1_Server'; break;
+			default: throw new Exception("WPS API version {$request->version} not supported");
+		}
+		// if (!empty($request->segments) && 'wsdl' == $request->segments[0]) {
+		// 	$serverClass = 'Api_WsdlServer';
+		// }
+
+		$idFiltrProces = null;
+		// foreach ($request->segments as $pathPart) {
+		// 	if ('filtr_proces_' == substr($pathPart, 0, 13)) {
+		// 		$idFiltrProces = (int)substr($pathPart, 13);
+		// 		if (!$idFiltrProces) throw new Api_WfsException("Wrong filtr process number");
+		// 		$this->DBG("filtr procesu({$idProcesFiltr})", __LINE__, __FUNCTION__, __CLASS__);
+		// 	}
+		// 	// if ('default_db' == $pathPart) continue;// skip 'default_db'
+		// 	// throw new Api_WfsException("Not implemented '{$pathPart}'", 501);// skip all - wsdl work on segments
+		// }
+
+		try {
+			$this->DBG("Api_WfsData->execute() START", __LINE__);
+			//$userAcl = User::getAcl();
+			IF(V::get('DBG','',$_GET)){echo'<pre style="max-height:200px;overflow:auto;border:1px solid red;text-align:left;">user (' . __CLASS__ . '::' . __FUNCTION__ . ':' . __LINE__ . '): ';print_r($this->_apiUser);echo'</pre>';}
+			$userAcl = new UserAcl($this->_apiUser->getID(), $use_cache = true);
+			$userAcl->fetchGroups();
+			if ($idFiltrProces) {
+				if (!$userAcl->canExecuteProcesInit($idFiltrProces)) {
+					throw new Api_WfsException("Access Denied for given process");
+				}
+				$userAcl->fetchProcesPerms($idFiltrProces);
+			} else {
+				$userAcl->fetchAllPerms();
+			}
+			User::getAcl($userAcl);// force set acl
+			IF(V::get('DBG','',$_GET)){echo'<pre style="max-height:200px;overflow:auto;border:1px solid red;text-align:left;">$userAcl (' . __CLASS__ . '::' . __FUNCTION__ . ':' . __LINE__ . '): ';print_r($userAcl);echo'</pre>';}
+
+			$this->DBG("usr:" . $this->_apiUser->getID(), __LINE__, __FUNCTION__, __CLASS__);
+			$wfsServer = new $serverClass($userAcl); // Api_WpsV1_Server, TODO: Api_WpsV2_Server
+			$wfsServer->setLogger($this->_logger);
+			$wfsServer->setBaseUri($this->_apiBaseUri);
+			$wfsServer->run($request);
+			exit;// TODO:? return $document;
+		} catch (Api_WfsException $e) {
+			DBG::logAuth($e);
+			$e->sendResponseXml();
+		} catch (Exception $e) {
+			DBG::logAuth($e);
+			$wfsException = new Api_WfsException($e->getMessage(), $e->getCode(), $e);
+			$wfsException->sendResponseXml();
+		}
+		$this->DBG("Api_WfsData->execute() END", __LINE__);
+
+		exit;
+		// return document tree - array of arrays
+	}
+
+}

+ 118 - 0
SE/se-lib/Api/WpsV1/DescribeProcess.php

@@ -0,0 +1,118 @@
+<?php
+
+Lib::loadClass('Api_WfsException');
+Lib::loadClass('Api_WfsNs');
+Lib::loadClass('Request');
+Lib::loadClass('Core_AclHelper');
+Lib::loadClass('Core_XmlWriter');
+
+class Api_WpsV1_DescribeProcess {
+
+	static function sendDescribeProcessXml($wpsServerUrl, $identifier) {
+		header('Content-type: application/xml; charset=utf-8');
+
+		$xmlWriter = new Core_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('wps:ProcessDescriptions');
+		$xmlWriter->writeAttribute('service', "WPS");
+		$xmlWriter->writeAttribute('version', "1.0.0");
+		// $xmlWriter->writeAttribute('xml:lang', "en");
+		$xmlWriter->writeAttribute('xmlns:xs', 'http://www.w3.org/2001/XMLSchema');
+		$xmlWriter->writeAttribute('xmlns:ows', "http://www.opengis.net/ows/1.1");
+		$xmlWriter->writeAttribute('xmlns:wps', "http://www.opengis.net/wps/1.0.0");
+		$xmlWriter->writeAttribute('xmlns:xlink', "http://www.w3.org/1999/xlink");
+		$xmlWriter->writeAttribute('xmlns:xsi', "http://www.w3.org/2001/XMLSchema-instance");
+		// $xmlWriter->writeAttribute('xsi:schemaLocation', "http://www.opengis.net/wps/1.0.0 ../wpsGetCapabilities_response.xsd");
+		// foreach (Api_WfsNs::getNsList() as $uri => $prefix) {
+		// 	$xmlWriter->writeAttribute("xmlns:{$prefix}", $uri);
+		// }
+		// $schemaLocations = [];
+		//$schemaLocations[] = 'http://www.opengis.net/wfs http://webgis.regione.sardegna.it:80/geoserver/schemas/wfs/1.0.0/WFS-capabilities.xsd';// @from http://webgis.regione.sardegna.it/geoserver/ows?service=WFS&request=GetCapabilities
+		// if (!empty($schemaLocations)) $xmlWriter->writeAttribute('xsi:schemaLocation', implode(' ', $schemaLocations));
+		$wpsProcess = self::getWpsProcess($identifier);
+		$xmlWriter->h('ProcessDescription', [
+			[ 'ows:Identifier', $wpsProcess->identifier ],
+			[ 'ows:Title', $wpsProcess->title ],
+			[ 'ows:Abstract', $wpsProcess->description ],
+			[ 'DataInputs', array_map(function ($dataInput) {
+				return [ 'Input', [ 'maxOccurs' => $dataInput->maxOccurs, 'minOccurs' => $dataInput->minOccurs ], [
+					[ 'ows:Identiier', $dataInput->identifier ],
+					[ 'ows:Title', $dataInput->title ],
+					[ 'ows:Abstract', $dataInput->description ],
+					('xml' === $dataInput->type)
+					? [ 'ComplexData', [
+							[ 'Default', [
+								[ 'Format', [
+									[ 'MimeType', "text/xml; subtype=gml/3.1.1" ],
+								] ],
+							] ],
+						] ]
+					: [
+							[ 'LiteralData', [
+								[ 'ows:AnyValue' ],
+							] ],
+						],
+				] ];
+			}, $wpsProcess->dataInputs) ],
+			[ 'ProcessOutputs', [
+				[ 'Output', [
+					[ 'ows:Identifier', "result" ],
+					[ 'ows:Title', "result" ],
+					[ 'ComplexOutput', [
+						[ 'Default', [
+							[ 'Format', [ [ 'MimeType', $wpsProcess->defaultOutput ] ] ],
+						] ],
+						[ 'Supported', array_map(function ($output) {
+							return [ 'Format', [ [ 'MimeType', $output ] ] ];
+						}, $wpsProcess->supportedOutput) ],
+						// [ 'Supported', [
+						// 	[ 'Format', [ [ 'MimeType', "text/xml; subtype=wfs-collection/1.0" ] ] ],
+						// 	[ 'Format', [ [ 'MimeType', "text/xml; subtype=wfs-collection/1.1" ] ] ],
+						// 	[ 'Format', [ [ 'MimeType', "application/json" ] ] ],
+						// 	[ 'Format', [ [ 'MimeType', "application/wfs-collection-1.0" ] ] ],
+						// 	[ 'Format', [ [ 'MimeType', "application/wfs-collection-1.1" ] ] ],
+						// 	[ 'Format', [ [ 'MimeType', "application/zip" ] ] ],
+						// ] ],
+					] ],
+				] ],
+			] ],
+		]);
+
+		$xmlWriter->endElement();// wps:ProcessDescriptions
+		$xmlWriter->endDocument();
+		exit;
+	}
+
+	static function getWpsProcess($identifier) { // TODO: get from WPS Process Factory // @return Type_WpsProcess
+		$wpsProcess = (object)[
+			'identifier' => $identifier,
+			'title' => "Title({$identifier})",
+			'description' => "Desc($identifier)",
+			'maxOccurs' => "1",
+			'minOccurs' => "1",
+			'dataInputs' => [
+				(object)[
+					'identifier' => $identifier,
+					'title' => $title,
+					'description' => $description,
+					'type' => 'literal',
+				],
+			],
+			// 'MimeType' => text/xml, 'Encoding' => base64, 'Schema' => http://foo.bar/gml/3.1.0/polygon.xsd
+			'defaultOutput' => [ 'MimeType' => "text/xml; subtype=wfs-collection/1.0" ],
+			'supportedOutput' => [
+				[ 'MimeType' => "text/xml; subtype=wfs-collection/1.0" ],
+				[ 'MimeType' => "text/xml; subtype=wfs-collection/1.1" ],
+				[ 'MimeType' => "application/json" ],
+				[ 'MimeType' => "application/wfs-collection-1.0" ],
+				[ 'MimeType' => "application/wfs-collection-1.1" ],
+				[ 'MimeType' => "application/zip" ],
+			]
+		];
+		return $wpsProcess;
+	}
+
+}

+ 233 - 0
SE/se-lib/Api/WpsV1/GetCapabilities.php

@@ -0,0 +1,233 @@
+<?php
+
+Lib::loadClass('Api_WfsException');
+Lib::loadClass('Api_WfsNs');
+Lib::loadClass('Request');
+Lib::loadClass('Core_AclHelper');
+Lib::loadClass('Core_XmlWriter');
+
+class Api_WpsV1_GetCapabilities { // TODO: ...
+
+	static function sendGetCapabilitiesCsv($wpsServerUrl, $serviceTitle, $serviceDescription, $aclList) {
+		throw new Api_WfsException("Not Implemented sendGetCapabilitiesCsv for Wps version 1.0.0", 501);
+		header('Content-Type: text/csv; charset=utf-8');
+		$csvLineSepartor = "\n";
+		$csvValueSepartor = ",";
+		$csvText = function ($value) {
+			return '"' . str_replace(['"'], ['\"'], $value) . '"';
+		};
+
+		echo implode(",", [
+			"Name",
+			"Title",
+			"namespace url",
+			"Keywords",
+			"Abstract",
+			"SRS",
+			"LatLongBoundingBox - minx",
+			"LatLongBoundingBox - miny",
+			"LatLongBoundingBox - maxx",
+			"LatLongBoundingBox - maxy",
+		]);
+		echo $csvLineSepartor;
+
+		echo implode($csvLineSepartor, array_map(function ($acl) use ($csvText, $csvValueSepartor) {
+			$ns = Core_AclHelper::parseNamespaceUrl($acl->getNamespace());
+			return implode($csvValueSepartor, [
+				"p5_{$ns['prefix']}:{$ns['name']}", // Name
+				$csvText($acl->getRawLabel()), // Title
+				Api_WfsNs::getNsUri($ns['prefix']), // namespace url
+				$csvText(implode(', ', [ $acl->getID(), $acl->getName(), $acl->getRawLabel() ])), // Keywords
+				$csvText($acl->getRawOpis()), // Abstract
+				'EPSG:4326', // SRS
+				"8.12328509871721", // LatLongBoundingBox - minx
+				"38.8575126897477", // LatLongBoundingBox - miny
+				"9.838674658246807", // LatLongBoundingBox - maxx
+				"41.31378404137082", // LatLongBoundingBox - maxy
+			]);
+		}, $aclList));
+		echo $csvLineSepartor;
+
+		echo implode($csvLineSepartor, array_map(function ($typeName) use ($csvText, $csvValueSepartor) {
+			list($prefix, $name) = explode(':', $typeName);
+			return implode($csvValueSepartor, [
+				"p5_{$prefix}:{$name}", // Name
+				$csvText($name), // Title
+				Api_WfsNs::getNsUri($prefix), // namespace url
+				$csvText($name), // Keywords
+				$csvText($name), // Abstract
+				'EPSG:4326', // SRS
+				"8.12328509871721", // LatLongBoundingBox - minx
+				"38.8575126897477", // LatLongBoundingBox - miny
+				"9.838674658246807", // LatLongBoundingBox - maxx
+				"41.31378404137082", // LatLongBoundingBox - maxy
+			]);
+		}, Core_AclHelper::getCustomAclList()));
+		exit;
+	}
+
+	static function sendGetCapabilitiesXml($wpsServerUrl, $serviceTitle, $serviceDescription, $aclList) {
+		header('Content-type: application/xml; charset=utf-8');
+		$xmlWriter = new Core_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('wps:Capabilities');
+		$xmlWriter->writeAttribute('service', "WPS");
+		$xmlWriter->writeAttribute('version', "1.0.0");
+		// $xmlWriter->writeAttribute('xml:lang', "en-GB");
+		$xmlWriter->writeAttribute('xmlns:xlink', "http://www.w3.org/1999/xlink");
+		$xmlWriter->writeAttribute('xmlns:wps', "http://www.opengis.net/wps/1.0.0");
+		$xmlWriter->writeAttribute('xmlns:ows', "http://www.opengis.net/ows/1.1");
+		$xmlWriter->writeAttribute('xmlns:xsi', "http://www.w3.org/2001/XMLSchema-instance");
+		// $xmlWriter->writeAttribute('xsi:schemaLocation', "http://www.opengis.net/wps/1.0.0 ../wpsGetCapabilities_response.xsd");
+		$xmlWriter->writeAttribute('updateSequence', "1");
+		$xmlWriter->writeAttribute('xmlns:ogc', "http://www.opengis.net/ogc");
+		// $xmlWriter->writeAttribute('xmlns', 'http://www.opengis.net/wfs');
+		// $xmlWriter->writeAttribute('xmlns:ogc', 'http://www.opengis.net/ogc');
+		// $xmlWriter->writeAttribute('xmlns:xsi', 'http://www.w3.org/2001/XMLSchema-instance');
+
+		foreach (Api_WfsNs::getNsList() as $uri => $prefix) {
+			$xmlWriter->writeAttribute("xmlns:{$prefix}", $uri);
+		}
+		$schemaLocations = [];
+		//$schemaLocations[] = 'http://www.opengis.net/wfs http://webgis.regione.sardegna.it:80/geoserver/schemas/wfs/1.0.0/WFS-capabilities.xsd';// @from http://webgis.regione.sardegna.it/geoserver/ows?service=WFS&request=GetCapabilities
+		if (!empty($schemaLocations)) $xmlWriter->writeAttribute('xsi:schemaLocation', implode(' ', $schemaLocations));
+		$xmlWriter->h('ows:ServiceIdentification', [
+			['ows:Title', $serviceTitle],
+			['ows:Abstract', $serviceDescription],
+			['ows:Keywords', [
+				['ows:Keyword', "WPS"],
+			] ],
+			['ows:ServiceType', "WPS"],
+			['ows:ServiceTypeVersion', "1.0.0"],
+			// ['ows:Profile', ...],
+				// Unordered list of identifiers of Application Profiles that are implemented by this server.
+				// This element should be included for each specified application profile implemented by this server.
+				// The identifier value should be specified by each Application Profile. If this element is omitted, no meaning is implied.
+			// ['ows:Fees', "NONE"],
+			// ['ows:AccessConstraints', "NONE"], // @from xsd: Unordered list of access constraints applied to assure the protection of privacy or intellectual property,
+				//  and any other restrictions on retrieving or using data from or otherwise using this server.
+				// The reserved value NONE (case insensitive) shall be used to mean no access constraints are imposed.
+				// When this element is omitted, no meaning is implied.
+		]);
+
+		// @from http://schemas.opengis.net/wps/1.0.0/examples/20_wpsGetCapabilities_response.xml
+		// 	<ows:ServiceProvider>
+		// 		<ows:ProviderName>Agriculture and Agri-Food Canada</ows:ProviderName>
+		// 		<ows:ProviderSite xlink:href="http://gis.agr.gc.ca/"/>
+		// 		<ows:ServiceContact>
+		// 			<ows:IndividualName>Peter Schut</ows:IndividualName>
+		// 			<ows:PositionName>Information System Scientist</ows:PositionName>
+		// 			<ows:ContactInfo>
+		// 				<ows:Phone>
+		// 					<ows:Voice>+1 613 759-1874</ows:Voice>
+		// 					<ows:Facsimile>+1 613 759-1937</ows:Facsimile>
+		// 				</ows:Phone>
+		// 				<ows:Address>
+		// 					<ows:DeliveryPoint>Room 1135, Neatby Building, 960, Carling Avenue</ows:DeliveryPoint>
+		// 					<ows:City>Ottawa</ows:City>
+		// 					<ows:AdministrativeArea>ON</ows:AdministrativeArea>
+		// 					<ows:PostalCode>K1AOC6</ows:PostalCode>
+		// 					<ows:Country>Canada</ows:Country>
+		// 					<ows:ElectronicMailAddress>schutp@agr.gc.ca</ows:ElectronicMailAddress>
+		// 				</ows:Address>
+		// 			</ows:ContactInfo>
+		// 		</ows:ServiceContact>
+		// 	</ows:ServiceProvider>
+		$xmlWriter->h('ows:ServiceProvider', [
+			[ 'ows:ProviderName', $_SERVER['SERVER_NAME'] ], // TODO: company name - from config?
+			[ 'ows:ProviderSite', [ 'xlink:href' => $wpsServerUrl ], null ],
+			// [ 'ows:ServiceContact', [
+			// 	[ 'ows:IndividualName', "..." ],
+			// ] ],
+		]);
+
+		$xmlWriter->h('ows:OperationsMetadata', [
+			[ 'ows:Operation', [ 'name' => "GetCapabilities" ], [
+				[ 'ows:DCP', [
+					[ 'ows:HTTP', [
+						[ 'ows:Get', [ 'xlink:href' => $wpsServerUrl ], null ],
+					] ]
+				] ]
+			] ],
+			[ 'ows:Operation', [ 'name' => "DescribeProcess" ], [
+				[ 'ows:DCP', [
+					[ 'ows:HTTP', [
+						[ 'ows:Get', [ 'xlink:href' => $wpsServerUrl ], null ],
+						// [ 'ows:Post', [ 'xlink:href' => $wpsServerUrl ], null ], // TODO: POST xml with DescribeProcess
+					] ]
+				] ]
+			] ],
+			[ 'ows:Operation', [ 'name' => "Execute" ], [
+				[ 'ows:DCP', [
+					[ 'ows:HTTP', [
+						[ 'ows:Get', [ 'xlink:href' => $wpsServerUrl ], null ],
+						// [ 'ows:Post', [ 'xlink:href' => $wpsServerUrl ], null ], // TODO: POST xml with DescribeProcess
+					] ]
+				] ]
+			] ],
+		]);
+
+		// @from http://schemas.opengis.net/wps/1.0.0/examples/20_wpsGetCapabilities_response.xml
+		// 	<wps:ProcessOfferings>
+		// 		<wps:Process wps:processVersion="1">
+		// 			<ows:Identifier>buffer</ows:Identifier>
+		// 			<ows:Title>Buffer a polygon feature</ows:Title>
+		// 			<ows:Abstract>Buffer  the polygon coordinates found in one GML stream by a given buffer distance, and output the results in GML.</ows:Abstract>
+		// 			<ows:Metadata xlink:title="buffer" />
+		// 			<ows:Metadata xlink:title="polygon" />
+		// 		</wps:Process>
+		// 	</wps:ProcessOfferings>
+		// 	<wps:Languages>
+		// 		<wps:Default>
+		// 			<ows:Language>en-CA</ows:Language>
+		// 		</wps:Default>
+		// 		<wps:Supported>
+		// 			<ows:Language>en-CA</ows:Language>
+		// 			<ows:Language>fr-CA</ows:Language>
+		// 		</wps:Supported>
+		// 	</wps:Languages>
+		// </wps:Capabilities>
+		$xmlWriter->h('wps:ProcessOfferings', [ // TODO:? for version 1.0.0 ?
+			[ 'wps:Process', [ 'wps:processVersion' => "1.0.0" ], [
+				[ 'ows:Identifier', "buffer" ],
+				[ 'ows:Title', "Buffer a polygon feature" ],
+				[ 'ows:Abstract', "Buffer the polygon coordinates found in one GML stream by a given buffer distance, and output the results in GML." ],
+			] ],
+			[ 'wps:Process', [ 'wps:processVersion' => "1.0.0" ], [
+				[ 'ows:Identifier', "JTS:area" ],
+				[ 'ows:Title', "Area" ],
+				[ 'ows:Abstract', "Returns the area of a geometry, in the units of the geometry. Assumes a Cartesian plane, so this process is only recommended for non-geographic CRSes." ],
+			] ]
+		]);
+
+		$xmlWriter->h('wps:Languages', [
+			[ 'wps:Default', [
+				[ 'ows:Language', "en-GB" ],
+			] ],
+			[ 'wps:Supported', [
+				[ 'ows:Language', "pl-PL" ],
+			] ]
+		]);
+
+		// $xmlWriter->h('wps:Contents', [
+		// 	[ 'wps:ProcessSummary', [ 'jobControlOptions' => "sync-execute async-execute dismiss" ], [
+		// 		[ 'ows:Title', "example 1" ],
+		// 		[ 'ows:Identifier', "{$wpsServerUrl}/task/example1" ],
+		// 	] ],
+		// 	[ 'wps:ProcessSummary', [ 'jobControlOptions' => "async-execute dismiss", 'processVersion' => "1.4.0" ], [
+		// 		[ 'ows:Title', "example 2" ],
+		// 		[ 'ows:Identifier', "{$wpsServerUrl}/task/example2" ],
+		// 	] ],
+		// ]);
+		// $xmlWriter->h('wps:WSDL', [ 'xlink:href' => "http://foo.bar/wps?WSDL" ], null);
+
+		$xmlWriter->endElement();// WFS_Capabilities
+		$xmlWriter->endDocument();
+		exit;
+	}
+
+}

Fichier diff supprimé car celui-ci est trop grand
+ 95 - 0
SE/se-lib/Api/WpsV1/Server.php


+ 1191 - 0
SE/se-lib/Api/WpsV1/ServerBase.php

@@ -0,0 +1,1191 @@
+<?php
+
+Lib::loadClass('Api_WfsException');
+Lib::loadClass('Api_WfsGeomTypeConverter');
+Lib::loadClass('Api_WfsNs');
+Lib::loadClass('Request');
+Lib::loadClass('Core_AclHelper');
+Lib::loadClass('Core_XmlWriter');
+
+class Api_WpsV1_ServerBase {
+
+	public $_usrAcl;
+	public $_typeConverter;
+	public $_apiBaseUri;
+	protected $_logFile;
+
+	public function __construct($usrAcl) {
+		$this->_usrAcl = $usrAcl;
+		$this->_typeConverter = new Api_WfsGeomTypeConverter();
+		$this->_apiBaseUri = '';
+	}
+
+	public function setBaseUri($uri) {
+		$this->_apiBaseUri = $uri;
+	}
+
+	public function getBaseUri() {// TODO: RMME
+		return $this->_apiBaseUri;
+	}
+
+	/**
+	 * @param string $typeName - 'p5_default_db:TEST_PERMS'
+	*/
+	public function getAclFromTypeName($typeName) {
+		try { // TODO: use object cache `CRM_#CACHE_ACL_OBJECT`
+			$namespace = str_replace([':', '__x3A__'], '/', $typeName);
+			if ('p5_' === substr($namespace, 0, 3)) $namespace = substr($namespace, 3);
+			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];
+		if (2 != count($typeEx)) throw new Api_WfsException("Could not get acl for '{$typeName}' - syntax error");
+		if ('p5_' == substr($sourceName, 0, 3)) $sourceName = substr($sourceName, 3);// remove prefix 'p5_'
+		$acl = $this->_usrAcl->getObjectAcl($sourceName, $objName);
+		$forceTblAclInit = 0;//('1' == V::get('_force', '', $_GET));
+		$acl->init($forceTblAclInit);
+		return $acl;
+	}
+
+	public function _getXmlSchemaLocation() {
+		$schemaLocations = array();
+		//$schemaLocations[] = 'http://www.opengis.net/wfs http://webgis.regione.sardegna.it:80/geoserver/schemas/wfs/1.0.0/WFS-capabilities.xsd';// @from http://webgis.regione.sardegna.it/geoserver/ows?service=WFS&request=GetCapabilities
+		return (!empty($schemaLocations))? 'xsi:schemaLocation="' . implode(' ', $schemaLocations) . '"' : '';
+	}
+
+	public function _printXmlNamespaceList() {
+		$listNs = array();
+		foreach (Api_WfsNs::getNsList() as $uri => $prefix) {
+			$listNs[] = 'xmlns:' . $prefix . '="' . $uri . '"';
+		}
+		return implode("\n", $listNs);
+	}
+
+	public function _getSourceNsList() {
+		$usrObjList = array();
+		$tblsAcl = $this->_usrAcl->getTablesAcl();
+		foreach ($tblsAcl as $tblAcl) {
+			$dataSourceName = 'default_db';// TODO: getSourceName
+			$tblName = $tblAcl->getName();
+			$usrObjList[] = array($dataSourceName, $tblName);
+		}
+		$usrObjList[] = array('objects', 'File');
+		$usrObjList[] = array('objects', 'TestPerms');
+		$usrObjList[] = array('objects', 'Korespondencja');
+		return $usrObjList;
+	}
+
+	public function _parseTransactionXmlStruct($requestXml, $requestXmlTags) {
+		$DBG = V::get('DBG_XML', 0, $_GET, 'int');// TODO: Profiler
+		$rootTagName = V::get('tag', '', $requestXmlTags[0]);
+		if ('Transaction' != $rootTagName) throw new Api_WfsException("Parse Request XML Error - Missing Transaction as root xml tag", __LINE__, null, 'TransactionParseError', 'request');
+
+		// TODO: special actions if action on nested objects
+		// 1. convert request: wfs.transaction.convert-wfs-request.xsl
+		// 2. validate converted request: wfs.transaction-converted-request.xsd
+		// 3. execute request in data source
+
+		// if($DBG){echo 'L.' . __LINE__ . ' $requestXmlTags:';print_r($requestXmlTags);echo "\n";}
+		/*
+				<Transaction
+				  xmlns="http://www.opengis.net/wfs"
+				  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+				  version="1.0.0"
+				  service="WFS"
+				  xmlns:p5_objects="https://biuro.biall-net.pl/wfs/objects"
+				  xmlns:gml="http://www.opengis.net/gml">
+				  <Insert xmlns="http://www.opengis.net/wfs">
+				    <TestPerms xmlns="https://biuro.biall-net.pl/wfs/objects">
+				      <plik xmlns="https://biuro.biall-net.pl/wfs/objects">
+				        <p5_objects:File>
+				          <p5_objects:name>blank-wfs.gif</p5_objects:name>
+				          <p5_objects:content>R0lGODlhAQABAIAAAP///////yH+EUNyZWF0ZWQgd2l0aCBHSU1QACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==</p5_objects:content>
+				        </p5_objects:File>
+				      </plik>
+				    </TestPerms>
+				  </Insert>
+				</Transaction>
+		*/
+		$actionXmlTags = array();// // [ 0 => [ 'action'=>Insert, 'typeName'=>str, 'tags'=>[] ]
+		{// split xml for action tags (Insert, Update, Delete)
+			$tagsCount = count($requestXmlTags);
+			for ($i = 1, $actionTagName = null, $actionIdx = -1, $tagLvl = 0; $i < $tagsCount - 1; $i++) {// skip Transaction open/close tag
+				$tag = $requestXmlTags[$i];
+				if (null == $actionTagName) {
+					$actionTagName = $tag['tag'];
+					$tagLvl = $tag['level'];
+					$actionIdx += 1;
+					$actionXmlTags[$actionIdx] = array();
+					$actionXmlTags[$actionIdx]['action'] = $actionTagName;
+					$actionXmlTags[$actionIdx]['typeName'] = V::get('typeName', '', $tag['attributes']);
+					$actionXmlTags[$actionIdx]['isDeepObject'] = null;// null - unknown, false - not seed, true - deep
+					$actionXmlTags[$actionIdx]['tags'] = array();
+				} else if ($tag['tag'] == $actionTagName && 'close' == $tag['type'] && $tagLvl == $tag['level']) {
+					$actionTagName = null;
+				} else {
+					$actionXmlTags[$actionIdx]['tags'][] = $tag;
+				}
+			}
+		}
+
+		{// Validate Request: WFS allow multiple tags inside Insert tag
+			// TODO: implement multiple tags in Insert tag if reauired. Use array_splice($actionXmlTags, $actionIdx, 0, $insertTags);
+			{// throw (Not Implemented, 501) if found multiple tags in Insert tag
+				foreach ($actionXmlTags as $actionIdx => $action) {
+					if ('Insert' !== $action['action']) continue;
+					$lvl = $action['tags'][0]['level'];
+					for ($i = 1, $cnt = count($action['tags']); $i < $cnt - 1; $i++) {
+						$tag = $action['tags'][$i];
+						// if($DBG){echo 'L.' . __LINE__ . " actionXmlTags loop({$i}) \$tag:";print_r($tag);echo "\n";}
+						if ($tag['level'] == $lvl) throw new Exception("Error Processing Request - multiple tags inside Insert tag is not implemented", 501);
+					}
+				}
+			}
+		}
+
+		{// Insert tag - fix typeName from first tag, remove first and last tag - leave only fields
+			foreach ($actionXmlTags as $actionIdx => $action) {
+				if ('Insert' !== $action['action']) continue;
+				array_pop($action['tags']);// remove last tag (close tag)
+				$tag = array_shift($action['tags']);// remove last tag (close tag)
+				$typeName = $tag['tag'];// eg. with prefix 'p5_objects:File' or without prefix but with @xmlns
+				if (false === strpos($typeName, ':')) {
+					$nsType = V::get('xmlns', '', $tag['attributes']);
+					if (!$nsType) throw new Exception("Error Processing Request - Missing object namespace '{$tag['tag']}'");
+					$prefix = Api_WfsNs::getNsPrefix($nsType);
+					if (!$prefix) {
+						if ($typeName == substr(rtrim($nsType, '/'), -1 * strlen($typeName))) {// typeName may be added to ns uri
+							$nsBaseForType = substr(rtrim($nsType, '/'), 0, -1 * strlen($typeName) - 1);
+							$prefix = Api_WfsNs::getNsPrefix($nsBaseForType);
+						}
+					}
+					if (!$prefix) throw new Exception("Error Processing Request - Unrecognized namespace uri '{$nsType}' for object '{$tag['tag']}'");
+					$typeName = "{$prefix}:{$typeName}";
+				}
+				$action['typeName'] = $typeName;
+				$actionXmlTags[$actionIdx] = $action;
+			}
+		}
+
+		{// validate
+			// if($DBG){echo 'L.' . __LINE__ . ' before validate $actionXmlTags:';print_r($actionXmlTags);echo "\n";}
+			foreach ($actionXmlTags as $actionIdx => $action) {
+				if ('Insert' == $action['action']) {
+					if (empty($action['typeName'])) throw new Exception("Error Processing Request - unknown object typeName to Insert");
+					$acl = $this->getAclFromTypeName($action['typeName']);
+					$actionXmlTags[$actionIdx] = $acl->validateInsertXml($action);
+				} else if ('Update' == $action['action']) {
+					$acl = $this->getAclFromTypeName($action['typeName']);
+					$actionXmlTags[$actionIdx] = $acl->validateUpdateXml($action);
+				} else if ('Delete' == $action['action']) {
+					if($DBG>1){echo'<pre>$action: ';print_r($action);echo'</pre>';}
+					$acl = $this->getAclFromTypeName($action['typeName']);
+					$actionXmlTags[$actionIdx] = $acl->validateDeleteXml($action);
+				} else {
+					if($DBG>1){echo'<pre>$action: ';print_r($action);echo'</pre>';}
+					throw new Exception("{$action['action']} action not implemented", 501);
+				}
+				// continue;// TODO: validate all by type
+			}
+		}
+
+		if ('1' == V::get('DBG_DONT_CHANGE_DB', '', $_REQUEST)) {
+			echo "----------------- action xml tags: ---------------" . "\n";
+			print_r($actionXmlTags);
+			die(".EOF\n");
+		}
+
+		{// execute
+			$returnIds = array();
+			$changesList = array();
+			foreach ($actionXmlTags as $actionIdx => $action) {
+				if ('Insert' == $action['action']) {
+					if (empty($action['typeName'])) throw new Exception("Error Processing Request - unknown object typeName to Insert");
+					$acl = $this->getAclFromTypeName($action['typeName']);
+					$newId = $acl->insertXml($action);
+					$returnIds[$actionIdx] = $newId;
+					$changesList[$actionIdx] = array('Status'=>(($newId > 0)? 'SUCCESS' : 'FAILED'), 'Message'=>"created {$newId}.", 'Action' => $action['action']);
+					if ($newId > 0) $changesList[$actionIdx]['fid'] = $acl->getName() . '.' . $newId;
+				} else if ('Update' == $action['action']) {
+					if($DBG>1){echo'<pre>$action: ';print_r($action);echo'</pre>';}
+					$acl = $this->getAclFromTypeName($action['typeName']);
+					$affected = $acl->updateXml($action);
+					$changesList[$actionIdx] = array('Status'=>(($affected >= 0)? 'SUCCESS' : 'FAILED'), 'Message'=>"affected {$affected}.", 'Action' => $action['action']);
+				} else if ('Delete' == $action['action']) {
+					$acl = $this->getAclFromTypeName($action['typeName']);
+					$affected = $acl->deleteXml($action);
+					$changesList[$actionIdx] = array('Status'=>(($affected >= 0)? 'SUCCESS' : 'FAILED'), 'Message'=>"deleted {$affected}.", 'Action' => $action['action']);
+				} else throw new Exception("TODO: {$action['action']} action not implemented", 501);
+			}
+			if($DBG){echo 'L.' . __LINE__ . ' $changesList:';print_r($changesList);echo "\n";}
+		}
+		return $this->_transactionResponse($changesList);
+	}
+
+	public function _transactionResponse($changesList) {
+		//  <WFS_TransactionResponse>
+		//    <TransactionResult>
+		//      <Status> : SUCCESS / FAILED / PARTIAL
+		//      [<Locator]
+		//      [<Message]
+		$messageTag = '';
+		$statusTag = '';
+		$statusIsFailed = false;
+		$statusAll = null;
+		$createdFeatureId = array();
+		foreach ($changesList as $featureId => $change) {
+			if ('FAILED' == $change['Status']) {
+				$statusIsFailed = true;
+			}
+			if ('SUCCESS' == $change['Status'] && !empty($change['fid'])) {
+				$createdFeatureId[] = $change['fid'];
+			}
+			// if (!empty($change['Message'])) $messageTag .= "Feature '{$featureId}' {$change['Status']}: {$change['Message']}\n";
+		}
+		$statusTag = ($statusIsFailed)? 'FAILED' : 'SUCCESS';
+		$statusTag = "<wfs:{$statusTag}/>";
+		$messageTag = '';//"<wfs:Message>{$messageTag}</wfs:Message>";
+		/* Example:
+		<?xml version="1.0" encoding="UTF-8"?>
+		<wfs:WFS_TransactionResponse version="1.0.0" xmlns:wfs="http://www.opengis.net/wfs"
+			xmlns:ogc="http://www.opengis.net/ogc" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+			xsi:schemaLocation="http://www.opengis.net/wfs http://localhost:8080/geoserver/schemas/wfs/1.0.0/WFS-transaction.xsd">
+			<wfs:InsertResult>
+				<ogc:FeatureId fid="archsites.26" />
+			</wfs:InsertResult>
+			<wfs:TransactionResult handle="Updating Signature rock label">
+				<wfs:Status>
+					<wfs:SUCCESS />
+				</wfs:Status>
+			</wfs:TransactionResult>
+		</wfs:WFS_TransactionResponse>*/
+		// TODO: build xml by DOMDocument
+		// TODO: xsi:schemaLocation="http://www.opengis.net/wfs http://localhost:8080/geoserver/schemas/wfs/1.0.0/WFS-transaction.xsd"
+		$wfsInsertResult = '';
+		if (!empty($createdFeatureId)) {
+			$wfsInsertResult = "\n<wfs:InsertResult>\n";
+			foreach ($createdFeatureId as $fid) {
+				$wfsInsertResult .= '<ogc:FeatureId fid="' . $fid . '" xmlns:ogc="http://www.opengis.net/ogc"/>' . "\n";
+			}
+			$wfsInsertResult .= "\n</wfs:InsertResult>\n";
+EOF;
+		}
+		$tranRes = <<<EOF
+<wfs:WFS_TransactionResponse version="1.0.0"
+		xmlns:wfs="http://www.opengis.net/wfs"
+		xmlns:ogc="http://www.opengis.net/ogc"
+		xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
+	{$wfsInsertResult}
+	<wfs:TransactionResult>
+		<wfs:Status>{$statusTag}</wfs:Status>
+		{$messageTag}
+	</wfs:TransactionResult>
+</wfs:WFS_TransactionResponse>
+EOF;
+		return $tranRes;
+	}
+
+	public function _convertTransactionXml($requestXmlString, $sourceNsList) {
+		$DBG = (V::get('DBG_XSL', '', $_GET) > 0);// TODO: Profiler
+		if($DBG){echo 'L.' . __LINE__ . ' sourceNsList:';print_r($sourceNsList);echo "\n";}
+		$updateActionsXsd = array();
+		$insertActionsXsd = array();
+		$deleteActionsXsd = array();
+		//<!-- TODO: create tag Update{X} where X is namespace index -->
+		foreach ($sourceNsList as $nsInd => $sourceNs) {
+			// <Update>
+			$theGeomField = 'the_geom';// TODO: get from fields list
+			$typeName = "p5_{$sourceNs[0]}:{$sourceNs[1]}";
+			if($DBG){echo 'L.' . __LINE__ . ' typeName:';print_r($typeName);echo "\n";}
+			$updateElementName = "UpdateNs{$nsInd}";
+			$geomCoordsUpdateXpath = "//wfs:Value/*/gml:outerBoundaryIs/gml:LinearRing/gml:coordinates";
+			$geomCoordsInsertXpath = "//*/gml:outerBoundaryIs/gml:LinearRing/gml:coordinates";
+			$acl = $this->getAclFromTypeName($typeName);
+			$geomType = $acl->getGeomFieldType($theGeomField);
+			if ('polygon' == $geomType) {
+				$geomCoordsUpdateXpath = ".//wfs:Value/*/gml:outerBoundaryIs/gml:LinearRing/gml:coordinates";
+				$geomCoordsUpdateXpath = "((<xsl:value-of select=\"{$geomCoordsUpdateXpath}\"/>))";
+				$geomCoordsInsertXpath = ".//*/gml:outerBoundaryIs/gml:LinearRing/gml:coordinates";
+				$geomCoordsInsertXpath = "((<xsl:value-of select=\"{$geomCoordsInsertXpath}\"/>))";
+			} else if ('linestring' == $geomType) {
+				$geomCoordsUpdateXpath = ".//wfs:Value/*/gml:coordinates";
+				$geomCoordsUpdateXpath = "(<xsl:value-of select=\"{$geomCoordsUpdateXpath}\"/>)";
+				$geomCoordsInsertXpath = ".//*/gml:coordinates";
+				$geomCoordsInsertXpath = "(<xsl:value-of select=\"{$geomCoordsInsertXpath}\"/>)";
+			} else if ('point' == $geomType) {
+				$geomCoordsUpdateXpath = ".//wfs:Value/*/gml:coordinates";
+				$geomCoordsUpdateXpath = "(<xsl:value-of select=\"{$geomCoordsUpdateXpath}\"/>)";
+				$geomCoordsInsertXpath = ".//*/gml:coordinates";
+				$geomCoordsInsertXpath = "(<xsl:value-of select=\"{$geomCoordsInsertXpath}\"/>)";
+			}
+			$actionXsd = <<<EOF
+					<xsl:when test="@typeName = '{$typeName}'">
+						<xsl:element name="{$updateElementName}">
+							<xsl:attribute name="typeName"><xsl:value-of select="@typeName" /></xsl:attribute>
+							<xsl:attribute name="featureId"><xsl:value-of select="ogc:Filter/ogc:FeatureId/@fid" /></xsl:attribute>
+							<xsl:for-each select="wfs:Property">
+								<xsl:element name="{wfs:Name}">
+									<xsl:choose>
+										<xsl:when test="wfs:Name = '{$theGeomField}'"><xsl:value-of select="local-name(//wfs:Value/*[1])"/>{$geomCoordsUpdateXpath}</xsl:when>
+										<xsl:otherwise><xsl:value-of select="wfs:Value"/></xsl:otherwise>
+									</xsl:choose>
+								</xsl:element>
+							</xsl:for-each>
+						</xsl:element>
+					</xsl:when>
+EOF;
+			$updateActionsXsd[] = $actionXsd;
+
+			$typeName = "{$sourceNs[1]}";//"p5_{$sourceNs[0]}:{$sourceNs[1]}";
+			$insertElementName = "InsertNs{$nsInd}";
+			$actionXsd = <<<EOF
+					<xsl:when test="local-name() = '{$typeName}'">
+						<xsl:element name="{$insertElementName}">
+							<xsl:attribute name="typeName"><xsl:value-of select="local-name()" /></xsl:attribute>
+							<xsl:attribute name="typeNsUri"><xsl:value-of select="namespace-uri()" /></xsl:attribute>
+							<xsl:for-each select="*">
+								<xsl:element name="{local-name()}">
+									<xsl:choose>
+										<xsl:when test="local-name() = '{$theGeomField}'"><xsl:value-of select="local-name(*[1])"/>{$geomCoordsInsertXpath}</xsl:when>
+										<xsl:otherwise><xsl:value-of select="."/></xsl:otherwise>
+									</xsl:choose>
+								</xsl:element>
+							</xsl:for-each>
+						</xsl:element>
+					</xsl:when>
+EOF;
+			$insertActionsXsd[] = $actionXsd;
+
+			$deleteElementName = "DeleteNs{$nsInd}";
+			$typeName = "p5_{$sourceNs[0]}:{$sourceNs[1]}";
+			$actionXsd = <<<EOF
+					<xsl:when test="@typeName = '{$typeName}'">
+						<xsl:variable name="typeName" select="@typeName" />
+						<xsl:for-each select="ogc:Filter/ogc:FeatureId">
+							<xsl:element name="{$deleteElementName}">
+								<xsl:attribute name="typeName"><xsl:value-of select="\$typeName" /></xsl:attribute>
+								<xsl:attribute name="featureId"><xsl:value-of select="@fid" /></xsl:attribute>
+							</xsl:element>
+						</xsl:for-each>
+					</xsl:when>
+EOF;
+			$deleteActionsXsd[] = $actionXsd;
+		}
+		if (!empty($updateActionsXsd)) {
+			$updateActionsXsd = implode("\n", $updateActionsXsd);
+			$updateActionsXsd = <<<EOF
+				<xsl:choose>
+					{$updateActionsXsd}
+				</xsl:choose>
+EOF;
+		} else {
+			$updateActionsXsd = '';
+		}
+		if (!empty($insertActionsXsd)) {
+			$insertActionsXsd = implode("\n", $insertActionsXsd);
+			$insertActionsXsd = <<<EOF
+				<xsl:choose>
+					{$insertActionsXsd}
+				</xsl:choose>
+EOF;
+		} else {
+			$insertActionsXsd = '';
+		}
+		if (!empty($deleteActionsXsd)) {
+			$deleteActionsXsd = implode("\n", $deleteActionsXsd);
+			$deleteActionsXsd = <<<EOF
+				<xsl:choose>
+					{$deleteActionsXsd}
+				</xsl:choose>
+EOF;
+		} else {
+			$deleteActionsXsd = '';
+		}
+
+		$convertTransactionXslString = '<?xml version="1.0"?>';
+		$convertTransactionXslString .= <<<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:template match="/">
+		<xsl:for-each select="wfs:Transaction">
+			<Transaction>
+				<xsl:attribute name="version"><xsl:value-of select="@version" /></xsl:attribute>
+				<xsl:attribute name="service"><xsl:value-of select="@service" /></xsl:attribute>
+				<xsl:for-each select="wfs:Update">
+					{$updateActionsXsd}
+				</xsl:for-each>
+				<xsl:for-each select="wfs:Insert/*">
+					{$insertActionsXsd}
+				</xsl:for-each>
+				<xsl:for-each select="wfs:Delete">
+					{$deleteActionsXsd}
+				</xsl:for-each>
+				<!-- TODO: Native -->
+			</Transaction>
+		</xsl:for-each>
+	</xsl:template>
+
+</xsl:transform>
+EOF;
+
+if($DBG){echo 'L.' . __LINE__ . ' $convertTransactionXslString:' . $convertTransactionXslString . "\n";}
+		$requestXml = new DOMDocument();
+		$requestXml->loadXml($requestXmlString);
+
+		$convertTransactionXsl = new DOMDocument();
+		$convertTransactionXsl->loadXml($convertTransactionXslString);
+		$proc = new XSLTProcessor();
+		$proc->importStylesheet($convertTransactionXsl);
+		return $proc->transformToXML($requestXml);
+	}
+
+	public function _validateConvertedTransactionXml($convertedTransaction, $sourceNsList) {
+		$DBG = (V::get('DBG_XSD', '', $_GET) > 0);// TODO: Profiler
+if($DBG){echo 'L.' . __LINE__ . ' sourceNsList:';print_r($sourceNsList);echo "\n";}
+
+		$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->setAttribute('elementFormDefault', 'qualified');
+		$rootNode->setAttribute('version', '1.0');
+
+		{// <xsd:element name="Transaction" type="TransactionType">
+			$elNode = $dom->createElementNS('http://www.w3.org/2001/XMLSchema', 'xsd:element');
+			$rootNode->appendChild($elNode);
+			$elNode->setAttribute('name', 'Transaction');
+			$elNode->setAttribute('type', 'TransactionType');
+			$cTypeNode = $dom->createElementNS('http://www.w3.org/2001/XMLSchema', 'xsd:complexType');
+			$rootNode->appendChild($cTypeNode);
+			$cTypeNode->setAttribute('name', 'TransactionType');
+				$seqNode = $dom->createElementNS('http://www.w3.org/2001/XMLSchema', 'xsd:sequence');
+				$cTypeNode->appendChild($seqNode);
+
+					$choiceNode = $dom->createElementNS('http://www.w3.org/2001/XMLSchema', 'xsd:choice');
+					$seqNode->appendChild($choiceNode);
+					$choiceNode->setAttribute('minOccurs', '0');
+					$choiceNode->setAttribute('maxOccurs', 'unbounded');
+
+					// <!-- <xsd:element ref="Update"/>	-->
+					foreach ($sourceNsList as $nsInd => $sourceNs) {
+						$typeName = "p5_{$sourceNs[0]}:{$sourceNs[1]}";
+						$updateElementName = "UpdateNs{$nsInd}";
+						$updateElementType = "UpdateNs{$nsInd}ElementType";
+						$updateElemNode = $dom->createElementNS('http://www.w3.org/2001/XMLSchema', 'xsd:element');
+						$choiceNode->appendChild($updateElemNode);
+						$updateElemNode->setAttribute('name', $updateElementName);
+						$updateElemNode->setAttribute('type', $updateElementType);
+					}
+					// <!-- <xsd:element ref="Insert"/>	-->
+					foreach ($sourceNsList as $nsInd => $sourceNs) {
+						$typeName = "p5_{$sourceNs[0]}:{$sourceNs[1]}";
+						$insertElementName = "InsertNs{$nsInd}";
+						$insertElementType = "InsertNs{$nsInd}ElementType";
+						$insertElemNode = $dom->createElementNS('http://www.w3.org/2001/XMLSchema', 'xsd:element');
+						$choiceNode->appendChild($insertElemNode);
+						$insertElemNode->setAttribute('name', $insertElementName);
+						$insertElemNode->setAttribute('type', $insertElementType);
+					}
+					// <!-- <xsd:element ref="Delete"/>	-->
+					foreach ($sourceNsList as $nsInd => $sourceNs) {
+						$typeName = "p5_{$sourceNs[0]}:{$sourceNs[1]}";
+						$deleteElementName = "DeleteNs{$nsInd}";
+						$deleteElementType = "DeleteNs{$nsInd}ElementType";
+						$deleteElemNode = $dom->createElementNS('http://www.w3.org/2001/XMLSchema', 'xsd:element');
+						$choiceNode->appendChild($deleteElemNode);
+						$deleteElemNode->setAttribute('name', $deleteElementName);
+						$deleteElemNode->setAttribute('type', $deleteElementType);
+					}
+					// <!-- <xsd:element ref="Native"/>	-->
+
+				$attrNode = $dom->createElementNS('http://www.w3.org/2001/XMLSchema', 'xsd:attribute');
+				$cTypeNode->appendChild($attrNode);
+				$attrNode->setAttribute('name', 'version');
+				$attrNode->setAttribute('type', 'xsd:string');
+				$attrNode->setAttribute('use', 'required');
+				$attrNode->setAttribute('fixed', '1.0.0');
+
+				$attrNode = $dom->createElementNS('http://www.w3.org/2001/XMLSchema', 'xsd:attribute');
+				$cTypeNode->appendChild($attrNode);
+				$attrNode->setAttribute('name', 'service');
+				$attrNode->setAttribute('type', 'xsd:string');
+				$attrNode->setAttribute('use', 'required');
+				$attrNode->setAttribute('fixed', 'WFS');
+		}
+
+		foreach ($sourceNsList as $nsInd => $sourceNs) {
+			$transactionTypesList = array();
+			$transactionTypesList[] = 'Update';
+			$transactionTypesList[] = 'Insert';
+			foreach ($transactionTypesList as $transactionType) {
+				$typeName = "p5_{$sourceNs[0]}:{$sourceNs[1]}";
+				if($DBG){echo 'L.' . __LINE__ . ' TODO: get acl typeName:';print_r($typeName);echo "\n";}
+				$acl = $this->getAclFromTypeName($typeName);
+				$updateElementName = "{$transactionType}Ns{$nsInd}";
+				$updateElementType = "{$transactionType}Ns{$nsInd}ElementType";
+
+	/*
+	<xsd:complexType name="{$updateElementType}">
+			<xsd:sequence>
+				<xsd:element name="PARENT_ID" minOccurs="0" maxOccurs="1" type="xsd:integer" />
+			</xsd:sequence>
+	*/
+				$updateTypeNode = $dom->createElementNS('http://www.w3.org/2001/XMLSchema', 'xsd:complexType');
+				$rootNode->appendChild($updateTypeNode);
+				$updateTypeNode->setAttribute('name', $updateElementType);
+				{
+					$seqNode = $dom->createElementNS('http://www.w3.org/2001/XMLSchema', 'xsd:all');
+					$updateTypeNode->appendChild($seqNode);
+					{
+						$pKeyField = $acl->getPrimaryKeyField();
+						$fldList = $this->_getFieldListFromAcl($acl);
+
+						// fields without geometry fields
+						foreach ($fldList as $fldName) {
+							if ($acl->isGeomField($fldName)) continue;
+
+							$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);
+
+							$fldType = null;
+							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';
+								$fldType = null;// 'xsd:string';
+								$patternDataTime = "(\d{4})-(\d{2})-(\d{2}) (\d{2}):(\d{2})(:(\d{2}))?";
+								// <xsd:element name="..." minOccurs="0" nillable="true">
+		            //     <xsd:simpleType>
+		            //         <xsd:restriction base="xsd:string">
+		            //             <xsd:pattern value="[a-zA-Z]+\(\((\-?\d+\.?\d*,\-?\d+\.?\d*)( \-?\d+\.?\d*,\-?\d+\.?\d*)+\)\)"/>
+		            //         </xsd:restriction>
+		            //     </xsd:simpleType>
+		            // </xsd:element>
+								$simpleTypeNode = $dom->createElementNS('http://www.w3.org/2001/XMLSchema', 'xsd:simpleType');
+								$restrictionNode = $dom->createElementNS('http://www.w3.org/2001/XMLSchema', 'xsd:restriction');
+								$patternNode = $dom->createElementNS('http://www.w3.org/2001/XMLSchema', 'xsd:pattern');
+								$restrictionNode->setAttribute('base', 'xsd:string');
+								$patternNode->setAttribute('value', $patternDataTime);
+								$restrictionNode->appendChild($patternNode);
+								$simpleTypeNode->appendChild($restrictionNode);
+								$elNode->appendChild($simpleTypeNode);
+								// continue;// TODO: ? below added nillable = true, minOccurs = 0, type = $fldType
+							}
+							else if ($acl->isBinaryField($fldName)) {
+								$fldType = 'xsd:base64Binary';
+							}
+							else {
+								$fldType = 'xsd:string';
+							}
+							if ($fldType) $elNode->setAttribute('type', $fldType);
+							$elNode->setAttribute('nillable', 'true');
+							$elNode->setAttribute('minOccurs', '0');
+						}
+
+						// only geometry fields
+						foreach ($fldList as $fldName) {
+							if (!$acl->isGeomField($fldName)) continue;
+
+							$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->isGeomField($fldName)) {
+								//$fldType = 'gml:GeometryPropertyType';
+								// TODO: use geom types from gml to wkt
+								// TODO: pattern wg atrybutów gml:coordinates decimal="." cs="," ts=" "
+								$patternWkt = '';// TODO: error if empty - unsupported geom type
+								$patternNum = '\-?\d+\.?\d*';
+								$patternPoint = $patternNum . ',' . $patternNum;
+								$patternPoints = '(' . $patternPoint . ')( ' . $patternPoint . ')+';
+
+								$geomType = $acl->getGeomFieldType($fldName);
+								if ('polygon' == $geomType) {
+									// [a-zA-Z]+\(\((\-?\d+\.?\d*,\-?\d+\.?\d*)( (\-?\d+\.?\d*,\-?\d+\.?\d*))+\)\)
+									$patternWkt = '[a-zA-Z]+\(\(' . $patternPoints . '\)\)';
+								} else if ('linestring' == $geomType) {
+									// [a-zA-Z]+\((\-?\d+\.?\d*,\-?\d+\.?\d*)( (\-?\d+\.?\d*,\-?\d+\.?\d*))+\)
+									$patternWkt = '[a-zA-Z]+\(' . $patternPoints . '\)';
+								} else if ('point' == $geomType) {
+									// [a-zA-Z]+\(\-?\d\.?\d*,\-?\d\.?\d*\)
+									$patternWkt = '[a-zA-Z]+\(' . $patternPoint . '\)';
+								}
+
+								$simpleTypeNode = $dom->createElementNS('http://www.w3.org/2001/XMLSchema', 'xsd:simpleType');
+								$restrictionNode = $dom->createElementNS('http://www.w3.org/2001/XMLSchema', 'xsd:restriction');
+								$patternNode = $dom->createElementNS('http://www.w3.org/2001/XMLSchema', 'xsd:pattern');
+								$restrictionNode->setAttribute('base', 'xsd:string');
+								$patternNode->setAttribute('value', $patternWkt);
+								$restrictionNode->appendChild($patternNode);
+								$simpleTypeNode->appendChild($restrictionNode);
+								$elNode->appendChild($simpleTypeNode);
+							}
+							$elNode->setAttribute('nillable', 'true');
+							$elNode->setAttribute('minOccurs', '0');
+						}
+					}
+				}
+
+				$attrNode = $dom->createElementNS('http://www.w3.org/2001/XMLSchema', 'xsd:attribute');
+				$updateTypeNode->appendChild($attrNode);
+				$attrNode->setAttribute('name', 'typeName');
+				$attrNode->setAttribute('type', 'xsd:token');
+				$attrNode->setAttribute('use', 'required');
+
+				if ($transactionType == 'Insert') {
+					$attrNode = $dom->createElementNS('http://www.w3.org/2001/XMLSchema', 'xsd:attribute');
+					$updateTypeNode->appendChild($attrNode);
+					$attrNode->setAttribute('name', 'typeNsUri');
+					$attrNode->setAttribute('type', 'xsd:anyURI');
+					$attrNode->setAttribute('use', 'required');
+				}
+				if ($transactionType == 'Update') {
+					$attrNode = $dom->createElementNS('http://www.w3.org/2001/XMLSchema', 'xsd:attribute');
+					$updateTypeNode->appendChild($attrNode);
+					$attrNode->setAttribute('name', 'featureId');
+					$attrNode->setAttribute('use', 'required');
+						$sTypeNode = $dom->createElementNS('http://www.w3.org/2001/XMLSchema', 'xsd:simpleType');
+						$attrNode->appendChild($sTypeNode);
+							$resNode = $dom->createElementNS('http://www.w3.org/2001/XMLSchema', 'xsd:restriction');
+							$sTypeNode->appendChild($resNode);
+							$resNode->setAttribute('base', 'xsd:string');
+								$patternNode = $dom->createElementNS('http://www.w3.org/2001/XMLSchema', 'xsd:pattern');
+								$resNode->appendChild($patternNode);
+								$patternNode->setAttribute('value', '[a-zA-Z_][a-zA-Z0-9_]*\.[0-9]*');
+				}
+			}
+			{// 'Delete'
+				$typeName = "p5_{$sourceNs[0]}:{$sourceNs[1]}";
+				$acl = $this->getAclFromTypeName($typeName);
+				$deleteElementType = "DeleteNs{$nsInd}ElementType";
+				$deleteTypeNode = $dom->createElementNS('http://www.w3.org/2001/XMLSchema', 'xsd:complexType');
+				$rootNode->appendChild($deleteTypeNode);
+				$deleteTypeNode->setAttribute('name', $deleteElementType);
+
+				/* <xsd:attribute name="typeName" type="xsd:token" use="required"/> */
+				$attrNode = $dom->createElementNS('http://www.w3.org/2001/XMLSchema', 'xsd:attribute');
+				$deleteTypeNode->appendChild($attrNode);
+				$attrNode->setAttribute('name', 'typeName');
+				$attrNode->setAttribute('type', 'xsd:token');
+				$attrNode->setAttribute('use', 'required');
+				/* <xsd:attribute name="featureId" use="required"> */
+				$attrNode = $dom->createElementNS('http://www.w3.org/2001/XMLSchema', 'xsd:attribute');
+				$deleteTypeNode->appendChild($attrNode);
+				$attrNode->setAttribute('name', 'featureId');
+				$attrNode->setAttribute('use', 'required');
+				$sTypeNode = $dom->createElementNS('http://www.w3.org/2001/XMLSchema', 'xsd:simpleType');
+				$attrNode->appendChild($sTypeNode);
+					$resNode = $dom->createElementNS('http://www.w3.org/2001/XMLSchema', 'xsd:restriction');
+					$sTypeNode->appendChild($resNode);
+					$resNode->setAttribute('base', 'xsd:string');
+						$patternNode = $dom->createElementNS('http://www.w3.org/2001/XMLSchema', 'xsd:pattern');
+						$resNode->appendChild($patternNode);
+						$patternNode->setAttribute('value', '[a-zA-Z_][a-zA-Z0-9_]*\.[0-9]*');
+			}
+		}
+
+		$validateConvertedTransactionXsdString = $dom->saveXml();
+
+if($DBG){echo 'L.' . __LINE__ . ' $validateConvertedTransactionXsdString:';print_r($validateConvertedTransactionXsdString);echo "\n";}
+		$reqXml = new DOMDocument();
+		$reqXml->loadXml($convertedTransaction);
+		// TODO: fetch PHP Warning: DOMDocument::schemaValidateSource(): Element 'PARENT_ID': 'abc' is not a valid value of the atomic type 'xs:integer'.
+		return $reqXml->schemaValidateSource($validateConvertedTransactionXsdString);
+	}
+
+	public function getInstanceFeatures($name, $args) {
+		$acl = $this->getAclFromTypeName("{$args['typePrefix']}:{$name}");
+		$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";
+
+		header('Content-type: application/xml; charset=utf-8');
+		$xmlWriter = new Core_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');
+		$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');
+		$xmlWriter->writeAttribute("xmlns:{$wfsNs}", $wfsNsUri);
+		if (!$simple) $xmlWriter->writeAttribute("xmlns:{$rootWfsNs}", $rootWfsNsUri);
+		$xmlWriter->writeAttribute('xsi:schemaLocation', "{$wfsNsUri} {$featureTypeUri}");
+		//     <gml:featureMember>
+		//         <p5_objects:TestPerms fid="TestPerms.64" p5:web_link="https://biuro.biall-net.pl/dev-pl/se-master/index.php?_route=ViewTableAjax&amp;namespace=default_objects/TestPerms#EDIT/64">
+		//             <p5_objects:ID p5:allow_write="true">64</p5_objects:ID>
+		$xmlWriter->endElement();// wfs:FeatureCollection
+		$xmlWriter->endDocument();
+		exit;
+	}
+
+	public function _describeInstanceAttributeTable($nsPrefix, $name) {
+		$acl = $this->getAclFromTypeName("{$nsPrefix}:{$name}");
+
+		header('Content-type: application/xml; charset=utf-8');
+		$xmlWriter = new Core_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('xsd:schema');
+		$xmlWriter->writeAttribute('xmlns:xsd', 'http://www.w3.org/2001/XMLSchema');
+		$xmlWriter->writeAttribute('xmlns:gml', 'http://www.opengis.net/gml');
+		foreach (Api_WfsNs::getNsList() as $uri => $prefix) {
+			$xmlWriter->writeAttribute("xmlns:{$prefix}", $uri);
+		}
+		$xmlWriter->writeAttribute('elementFormDefault', 'qualified');
+
+		$xsdInstanceType = $acl->getName() . "_instanceType";
+		$xsdPrimaryKey = "xsd:string";// TODO: get from $acl
+		$xmlWriter->h('xsd:element', ['name'=>"instance"], [
+			[ 'xsd:complexType', [
+				[ 'xsd:sequence', [
+					[ 'xsd:element', ['name'=>"primaryKey", 'type'=>$xsdPrimaryKey], null ],
+					[ 'xsd:element', ['name'=>"instance_name", 'type'=>$xsdInstanceType], null ],
+					[ 'xsd:element', ['name'=>"instance_type", 'type'=>"xsd:string"], null ],// TODO: instance, derived, matching
+					[ 'xsd:element', ['name'=>"create_author", 'type'=>"xsd:string"], null ],
+					[ 'xsd:element', ['name'=>"create_date", 'type'=>"xsd:dateTime"], null ],
+					[ 'xsd:element', ['name'=>"update_author", 'type'=>"xsd:string"], null ],
+					[ 'xsd:element', ['name'=>"updage_date", 'type'=>"xsd:dateTime"], null ],
+					[ 'xsd:element', ['name'=>"verified", 'type'=>"xsd:integer"], null ],
+				] ]
+			] ]
+		]);
+		$instanceList = (method_exists($acl, 'getInstanceList'))
+			? array_map(function ($instanceName) {
+				return [ 'xsd:enumeration', ['value'=>$instanceName], null ];
+			}, $acl->getInstanceList())
+			: [ [ 'xsd:enumeration', ['value'=>$acl->getName()], null ] ]
+		;
+		$xmlWriter->h('xsd:simpleType', ['name'=>$xsdInstanceType], [
+			[ 'xsd:restriction', ['base'=>"xsd:string"], $instanceList ],
+		]);
+		$xmlWriter->endElement();// xsd:schema
+		$xmlWriter->endDocument();
+		exit;
+	}
+
+	public function _getDescribeFeatureType($nsPrefix, $type, $simple = true) {
+		return $this->_getDescribeFeatureTypes(array(array($nsPrefix, $type)), $simple);
+	}
+
+	public function _parseDescribeFeatureTypeRequest($reqContent, $simple = true) {
+		$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 ('DescribeFeatureType' != $rootTagName) {
+			throw new Api_WfsException("Wrong xml root tag '{$rootTagName}' #" . __LINE__, 501);
+		}
+		$requestXmlTags = $tags;
+		$DBG = (V::get('DBG_XML', '', $_GET) > 0);// TODO: Profiler
+		$rootTagName = V::get('tag', '', $requestXmlTags[0]);
+		if ('DescribeFeatureType' != $rootTagName) {
+			throw new Exception("Parse Request xml error #" . __LINE__);
+		}
+		/*[1] => Array(
+						[tag] => TypeName
+						[type] => complete
+						[level] => 2
+						[value] => p5_default_db:Rozdzielcza_rurociag_wsg84)
+		*/
+		$typeNames = array();
+		$totalTypes = count($requestXmlTags) - 1;
+		for ($i = 1; $i < $totalTypes; $i++) {
+			if($DBG){echo "TAG[{$i}]:" . json_encode($requestXmlTags[$i]) . "\n";}
+			$typeNames[] = explode(':', $requestXmlTags[$i]['value'], 2);
+		}
+		//echo "typeNames: " . json_encode($typeNames) . "\n";
+		return $this->_getDescribeFeatureTypes($typeNames, $simple);
+	}
+
+	public function _getDescribeFeatureAllTypes($simple = true) {
+		$db = DB::getDB();
+		$idDefaultDB = $db->_zasob_id;
+
+		$tblsAcl = $this->_getTableAclList();
+		foreach ($tblsAcl as $tblAcl) {
+			$dataSourceName = 'default_db';// TODO: getSourceName
+			$tblName = $tblAcl->getName();
+			$typeNames[] = array("p5_{$dataSourceName}", $tblName);
+		}
+		return $this->_getDescribeFeatureTypes($typeNames, $simple);
+	}
+
+	// @param $typeNames = array( array( $nsPrefix, $type ) )
+	public function _getDescribeFeatureTypes($typeNames, $simple = true) {
+		if (empty($typeNames)) throw new HttpException("Feature Type Names not defined", 400);
+		$this->DBG("types:" . json_encode($typeNames), __LINE__, __FUNCTION__, __CLASS__);
+		DBG::log($typeNames, 'array', "DescribeFeatureType \$typeNames");
+		// TODO: fix namespace BUG for multiple types:
+		//  - fetch namespace for first type
+		//  - if another object has another namespace then -> import tag
+
+		$baseNsUri = Api_WfsNs::getBaseWfsUri();
+		$rootWfsNs = 'p5';
+		$rootWfsNsUri = "{$baseNsUri}";
+		$featureTypeUri = Api_WfsNs::getBaseWfsUri() . "?SERVICE=WFS&VERSION=1.0.0&REQUEST=DescribeFeatureType";
+
+		header('Content-type: application/xml');
+		$nsMap = Api_WfsNs::getNsList();// uri => prefix
+		$xsdTargetNamespace = null;
+		{ // targetNamespace
+			list($nsPrefix, $objectName) = reset($typeNames);
+			$typeName = "{$nsPrefix}:{$objectName}";
+			$acl = $this->getAclFromTypeName($typeName);
+			$aclNamespaceUri = Api_WfsNs::getNsUri($acl->getSourceName());
+			$xsdTargetNamespace = $aclNamespaceUri;
+			if (!array_key_exists($aclNamespaceUri, $nsMap)) $nsMap[$aclNamespaceUri] = $acl->getSourceName();
+		}
+
+		$xmlWriter = new Core_XmlWriter();
+		if (!$xmlWriter) throw new HttpException("Error no XMLWriter", 404);
+		$xmlWriter->openMemory();// openUri('php://output');
+		$xmlWriter->setIndent(true);
+		$xmlWriter->startDocument('1.0','UTF-8');
+		$xmlWriter->startElement('xsd:schema');
+		$xmlWriter->writeAttribute('xmlns:xsd', 'http://www.w3.org/2001/XMLSchema');
+		$xmlWriter->writeAttribute('xmlns:gml', 'http://www.opengis.net/gml');
+		foreach (Api_WfsNs::getNsList() as $uri => $prefix) {
+			$xmlWriter->writeAttribute("xmlns:{$prefix}", $uri);
+		}
+		$xmlWriter->writeAttribute('elementFormDefault', "qualified");
+		if ($xsdTargetNamespace) $xmlWriter->writeAttribute('targetNamespace', $xsdTargetNamespace);
+		$schemaLocations = [];
+		//$schemaLocations[] = 'http://www.opengis.net/wfs http://webgis.regione.sardegna.it:80/geoserver/schemas/wfs/1.0.0/WFS-capabilities.xsd';// @from http://webgis.regione.sardegna.it/geoserver/ows?service=WFS&request=GetCapabilities
+		if (!empty($schemaLocations)) $xmlWriter->writeAttribute('xsi:schemaLocation', implode(' ', $schemaLocations));
+		$xmlWriter->writeAttribute('version', "1.0.0");
+		$xmlWriter->h('xsd:import', [
+			'namespace' => "http://www.opengis.net/gml",
+			'schemaLocation' => Request::getPathUri() . "schema/gml/2.1.2/feature.xsd"
+		], null);
+		foreach ($typeNames as $typeNameEx) {
+			list($nsPrefix, $objectName) = $typeNameEx;
+			$typeName = "{$nsPrefix}:{$objectName}";
+			$xmlWriter->writeComment("typeName '{$typeName}'");
+			$acl = $this->getAclFromTypeName($typeName);
+			$aclNamespaceUri = Api_WfsNs::getNsUri($acl->getSourceName());
+			if (!array_key_exists($aclNamespaceUri, $nsMap)) $nsMap[$aclNamespaceUri] = $acl->getSourceName();
+			if ($xsdTargetNamespace != $aclNamespaceUri) {
+				$xmlWriter->writeComment("TODO: typeName '{$typeName}' by import namespace '{$aclNamespaceUri}'");// TODO: <xsd:import>; continue;
+			}
+
+			DBG::log($acl->hasSimpleSchema(), 'array', "\$acl({$typeName})->hasSimpleSchema()");
+			if ($acl->hasSimpleSchema()) {
+				$simpleSchema = $acl->getSimpleSchema();
+				$xmlWriter->writeComment("TODO: typeName '{$typeName}' hasSimpleSchema L." . __LINE__);
+
+				$aliasRefMap = array();// fieldName => namespace uri
+				foreach ($simpleSchema as $ssName => $schema) {
+					if ('root' == $ssName) $ssName = $objectName;
+					foreach ($schema as $fieldName => $field) {
+						if (is_array($field)
+							&& !empty($field['@ref'])
+							&& false !== strpos($field['@ref'], '/')
+						) {// @ref_uri
+							$aliasRefMap[ "{$ssName}_{$fieldName}" ] = $field['@ref'];
+						}
+					}
+				}
+				if (!empty($aliasRefMap)) {
+					foreach ($aliasRefMap as $fieldName => $aliasNsUri) {
+						list($nsUri, $prefix, $name) = Api_WfsNs::parseObjectNsUri($aliasNsUri);
+						if (!array_key_exists($nsUri, $nsMap)) $nsMap[$nsUri] = $prefix;
+						$xmlWriter->h('xsd:import', ['namespace' => $nsUri, 'schemaLocation' => "{$nsUri}.xsd"], null); // TODO: real file url -> DescribeFeatureType[Advanced]
+					}
+				}
+
+				foreach ($simpleSchema as $ssName => $schema) {
+					{// code from Code_AclSimpleSchema
+						if ('root' == $ssName) $ssName = $objectName;
+
+						// <xsd:complexType name="ZaliczkaPozycjaType">
+				    //     <xsd:complexContent>
+				    //         <xsd:extension base="gml:AbstractFeatureType">
+				    //             <xsd:sequence>
+				    //                 <xsd:element minOccurs="0" maxOccurs="1" name="id" type="xsd:integer" nillable="true"/>
+				    //                 <xsd:element minOccurs="0" maxOccurs="1" name="created" type="xsd:date" nillable="true"/>
+				    //                 <xsd:element minOccurs="0" maxOccurs="1" ref="default_objects/AccessOwner" p5:name="worker"/>
+				    //                 <xsd:element minOccurs="0" maxOccurs="1" name="kwota" type="xsd:decimal" nillable="true"/>
+				    //                 <xsd:element minOccurs="0" maxOccurs="1" ref="ZaliczkaPozycja" p5:name="pozycja"/>
+				    //             </xsd:sequence>
+				    //         </xsd:extension>
+				    //     </xsd:complexContent>
+				    // </xsd:complexType>
+						$tnsPrefix = $acl->getSourceName();
+						$xmlWriter->startElement('xsd:complexType');
+						$xmlWriter->writeAttribute('name', "{$ssName}Type");
+						$xmlWriter->startElement('xsd:sequence');
+						foreach ($schema as $fieldName => $field) {
+							// [@namespace] => default_db/ZALICZKA_POZYCJA/ZaliczkaPozycja
+	            // [id] => xsd:integer
+	            // [kwota] => xsd:decimal
+	            // [korespondencja] => [ '@ref' => Korespondencja ]
+	            // [projekt] => [ '@ref' => Projekt ]
+							// TODO: p5:field_name
+							if ('@' == substr($fieldName, 0, 1)) continue;// skip tags
+							$xmlWriter->startElement('xsd:element');
+							if (!is_array($field)) throw new Exception("Error Processing simpleSchema: '{$ssName}/{$fieldName}'");
+							if (!empty($field['@type'])) {
+								$xmlWriter->writeAttribute('name', $fieldName);
+								$xmlWriter->writeAttribute('type', $field['@type']);
+								$xmlWriter->writeAttribute('nillable', "true");
+							} else if (!empty($field['@ref'])) {
+								if (false !== strpos($field['@ref'], '/')) {// @ref_uri
+									$xmlWriter->writeAttribute('ref', "{$tnsPrefix}:{$ssName}_{$fieldName}");
+									$xmlWriter->writeAttributeNS($rootWfsNs, "name", $rootWfsNsUri, $fieldName);
+								} else {
+									$xmlWriter->writeAttribute('ref', "{$tnsPrefix}:{$field['@ref']}");
+									if ($fieldName != $field['@ref']) {
+										$xmlWriter->writeAttributeNS($rootWfsNs, "name", $rootWfsNsUri, $fieldName);
+									}
+								}
+							} else {
+								throw new Exception("Error Processing simpleSchema - missing @type or @ref: '{$ssName}/{$fieldName}'");
+							}
+							if (array_key_exists('@minOccurs', $field)) $xmlWriter->writeAttribute('minOccurs', $field['@minOccurs']);
+							if (array_key_exists('@maxOccurs', $field)) $xmlWriter->writeAttribute('maxOccurs', $field['@maxOccurs']);
+							$xmlWriter->endElement(); // 'xsd:element'
+						}
+						$xmlWriter->endElement(); // 'xsd:sequence'
+						$xmlWriter->endElement(); // 'xsd:complexType'
+
+						$xmlWriter->startElement('xsd:element');
+						$xmlWriter->writeAttribute('name', $ssName);
+						$xmlWriter->writeAttribute('type', "{$tnsPrefix}:{$ssName}Type");
+						if (!$simple) {
+							if (!empty($schema['@namespace'])) {// TODO: @namespace is required?
+								list($nsUri, $prefix, $name) = Api_WfsNs::parseObjectNsUri($schema['@namespace']);
+								$xmlWriter->writeAttributeNS($rootWfsNs, "namespace", $rootWfsNsUri, "{{$nsUri}}{$name}");
+							}
+						}
+						$xmlWriter->endElement(); // 'xsd:element'
+					}
+				}
+
+				if (!empty($aliasRefMap)) {
+					foreach ($aliasRefMap as $fieldName => $aliasNsUri) {
+						list($nsUri, $prefix, $name) = Api_WfsNs::parseObjectNsUri($aliasNsUri);
+						$xmlWriter->h('xsd:element', ['name' => $fieldName, 'type' => "{$prefix}:{$name}Type"], null);
+					}
+				}
+			} else {
+				$objectXsdName = "{$objectName}Type";
+				$xmlWriter->startElement('xsd:complexType');
+				$xmlWriter->writeAttribute('name', $objectXsdName);
+				// if (!$simple) $xmlWriter->writeAttribute("xlmns:{$rootWfsNs}", $rootWfsNsUri);
+				if (!$simple) $xmlWriter->writeAttributeNS($rootWfsNs, "web_link", $rootWfsNsUri, Request::getPathUri() . "index.php?_route=ViewTableAjax&namespace=" . $acl->getNamespace());
+				if (!$simple && ($lastUpdateDate = $acl->lastUpdateDate())) $xmlWriter->writeAttributeNS($rootWfsNs, "last_update_date", $rootWfsNsUri, $lastUpdateDate);
+				$xmlWriter->startElement('xsd:complexContent');
+				$xmlWriter->startElement('xsd:extension');
+				$xmlWriter->writeAttribute('base', "gml:AbstractFeatureType");
+				$xmlWriter->startElement('xsd:sequence');
+				$pKeyField = $acl->getPrimaryKeyField();
+				$p5Attributes = ($simple)? array() : $acl->getAttributesFromZasoby();
+				$fldList = $this->_getFieldListFromAcl($acl);
+				foreach ($fldList as $fldName) {
+					$xmlWriter->startElement('xsd:element');
+					// TODO: get minOccurs from $acl->xsd()
+					$xmlWriter->writeAttribute('minOccurs', (method_exists($acl, 'getXsdMinOccurs'))
+						? $acl->getXsdMinOccurs($fldName)
+						: (($pKeyField == $fldName) ? '1' : '0')
+					);
+					$xmlWriter->writeAttribute('maxOccurs', (method_exists($acl, 'getXsdMaxOccurs'))
+						? $acl->getXsdMaxOccurs($fldName)
+						: '1'
+					);
+					$fldType = $acl->getXsdFieldType($fldName);
+					if (!$simple && $acl->isEnumerationField($fldName)) {
+						$fldType = $acl->getSourceName() . ":{$fldName}Type";
+					}
+					if ('ref:' == substr($fldType, 0, 4)) {
+						$xmlWriter->writeAttribute("ref", substr($fldType, 4));
+						$xmlWriter->writeAttributeNS($rootWfsNs, "name", $rootWfsNsUri, $fldName);
+					} else if ('local_ref:' == substr($fldType, 0, 10)) {
+						$xmlWriter->writeAttribute("type", "{$fldName}Type");
+						$xmlWriter->writeAttributeNS($rootWfsNs, "name", $rootWfsNsUri, $fldName);
+					} else if ('alias_ref:' == substr($fldType, 0, 10)) {
+						$xmlWriter->writeAttribute("ref", $acl->getSourceName() . ":{$fldName}");
+						$xmlWriter->writeAttributeNS($rootWfsNs, "name", $rootWfsNsUri, $fldName);
+					} else {
+						$xmlWriter->writeAttribute('name', $fldName);
+						$xmlWriter->writeAttribute('type', $fldType);
+						$xmlWriter->writeAttribute('nillable', 'true');// nillable not allowed in ref
+					}
+					if (!$simple) {
+						if (!empty($p5Attributes[$fldName])) {
+							$p5attrs = $p5Attributes[$fldName];
+							if (!empty($p5attrs['id_zasob'])) $xmlWriter->writeAttributeNS($rootWfsNs, "id_zasob", $rootWfsNsUri, $p5attrs['id_zasob']);
+							if (!empty($p5attrs['label'])) $xmlWriter->writeAttributeNS($rootWfsNs, "label", $rootWfsNsUri, $p5attrs['label']);
+							if (!empty($p5attrs['description'])) $xmlWriter->writeAttributeNS($rootWfsNs, "description", $rootWfsNsUri, $p5attrs['description']);
+						}
+						if ($acl->canWriteField($fldName)) $xmlWriter->writeAttributeNS($rootWfsNs, "allow_write", $rootWfsNsUri, "true");
+						if ($acl->canCreateField($fldName)) $xmlWriter->writeAttributeNS($rootWfsNs, "allow_create", $rootWfsNsUri, "true");
+						if (!$acl->canReadField($fldName)) $xmlWriter->writeAttributeNS($rootWfsNs, "allow_read", $rootWfsNsUri, "false");
+					}
+					$xmlWriter->endElement(); // xsd:element
+				}
+				$xmlWriter->endElement(); // xsd:sequence
+				if (!$simple) $xmlWriter->h('xsd:attribute', ['name' => "instance", 'type' => $acl->getSourceName() . ":instanceType"], null);
+				$xmlWriter->endElement(); // xsd:extension
+				$xmlWriter->endElement(); // xsd:complexContent
+				$xmlWriter->endElement(); // xsd:complexType
+
+				if (!$simple) {
+					$xsdInstanceList = (method_exists($acl, 'getInstanceList'))
+						? array_map(function ($instanceName) {
+							return [ 'xsd:enumeration', ['value'=>$instanceName], null ];
+						}, $acl->getInstanceList())
+						: [ [ 'xsd:enumeration', ['value'=>$acl->getName()], null ] ]
+					;
+					DBG::log($xsdInstanceList, 'array', "\$xsdInstanceList");
+					$xmlWriter->h('xsd:simpleType', ['name' => 'instanceType'], [
+						[ 'xsd:restriction', ['base' => 'xsd:string'], $xsdInstanceList ]
+					]);
+				}
+
+				$xmlWriter->h('xsd:element', ['name' => $objectName, 'type' => $acl->getSourceName() . ':' . $objectXsdName, 'substitutionGroup'=>"gml:_Feature"], null);
+
+				foreach ($fldList as $fldName) {
+					$fldType = $acl->getXsdFieldType($fldName);
+					if ('alias_ref:' == substr($fldType, 0, 10)) {
+						$localRefType = substr($fldType, 10);
+						$xmlWriter->h('xsd:element', ['name' => $fldName, 'type' => $localRefType], null);
+					} else if ('local_ref:' == substr($fldType, 0, 10)) {
+						$localRefType = substr($fldType, 10);
+						$xmlWriter->writeComment("TODO:
+							<xsd:complexType name=\"produkt_Type\">
+								<xsd:sequence>
+									<xsd:element name=\"idProd\" type=\"xsd:integer\" />
+									<xsd:element name=\"nazwa\" type=\"xsd:string\" />
+									<xsd:element name=\"cena\" type=\"xsd:decimal\" />
+								</xsd:sequence>
+							</xsd:complexType>
+						");
+					}
+				}
+
+				if (!$simple) {
+					foreach ($fldList as $fldName) {
+						if (!$acl->isEnumerationField($fldName)) continue;
+						$xsdEnumList = [];
+						$enum = $acl->getEnumerations($fldName);
+						foreach ($enum as $val => $label) {
+							$xsdEnum = ['xsd:enumeration', ['value' => $val], null];
+							if (!empty($p5Attributes[$fldName]['valuesMap'][$val])) {
+								$xsdEnum[1]["xmlns:{$rootWfsNs}"] = $rootWfsNsUri;
+								$xsdEnum[1]["{$rootWfsNs}:label"] = $p5Attributes[$fldName]['valuesMap'][$val];
+							}
+							$xsdEnumList[] = $xsdEnum;
+						}
+						$xmlWriter->h('xsd:simpleType', ['name' => "{$fldName}Type"], [
+							[ 'xsd:restriction', ['base' => "xsd:string"], $xsdEnumList ]
+						]);
+					}
+				}
+			}
+		}
+		$xmlWriter->endElement(); // 'xsd:schema'
+		$xmlWriter->endDocument();
+		echo $xmlWriter->outputMemory($flush = true);
+	}
+
+	public function _getTableAclList() {// Use only Tables from default_db
+		$tblAclList = array();
+		$idDefaultDB = DB::getPDO()->getZasobId();
+		$fullTblAclList = $this->_usrAcl->getTablesAcl();
+		foreach ($fullTblAclList as $tblAcl) {
+			if ($idDefaultDB != $tblAcl->getDB()) {// hide non default_db tables
+				continue;
+			}
+			// $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
+			// 	continue;
+			// }
+			$tblAclList[] = $tblAcl;
+		}
+		return $tblAclList;
+	}
+
+	public function _getFieldListFromAcl($acl) {
+		$fldList = $acl->getRealFieldListByIdZasob();
+		return $fldList;
+	}
+
+	public function setLogger($logger) {
+		$this->_logger = $logger;
+	}
+
+	public function DBG($reqLog, $lineNr = null, $funName = null, $className = null) {
+		if (!$this->_logger) return;
+		$this->_logger->DBG($reqLog, $lineNr, $funName, $className);
+	}
+
+}

+ 222 - 0
SE/se-lib/Api/WpsV2/GetCapabilities.php

@@ -0,0 +1,222 @@
+<?php
+
+Lib::loadClass('Api_WfsException');
+Lib::loadClass('Api_WfsNs');
+Lib::loadClass('Request');
+Lib::loadClass('Core_AclHelper');
+Lib::loadClass('Core_XmlWriter');
+
+class Api_WpsV2_GetCapabilities { // TODO: ...
+
+	static function sendGetCapabilitiesCsv($wpsServerUrl, $serviceTitle, $serviceDescription, $aclList) {
+		throw new Api_WfsException("Not Implemented sendGetCapabilitiesCsv for Wps version 1.0.0", 501);
+		header('Content-Type: text/csv; charset=utf-8');
+		$csvLineSepartor = "\n";
+		$csvValueSepartor = ",";
+		$csvText = function ($value) {
+			return '"' . str_replace(['"'], ['\"'], $value) . '"';
+		};
+
+		echo implode(",", [
+			"Name",
+			"Title",
+			"namespace url",
+			"Keywords",
+			"Abstract",
+			"SRS",
+			"LatLongBoundingBox - minx",
+			"LatLongBoundingBox - miny",
+			"LatLongBoundingBox - maxx",
+			"LatLongBoundingBox - maxy",
+		]);
+		echo $csvLineSepartor;
+
+		echo implode($csvLineSepartor, array_map(function ($acl) use ($csvText, $csvValueSepartor) {
+			$ns = Core_AclHelper::parseNamespaceUrl($acl->getNamespace());
+			return implode($csvValueSepartor, [
+				"p5_{$ns['prefix']}:{$ns['name']}", // Name
+				$csvText($acl->getRawLabel()), // Title
+				Api_WfsNs::getNsUri($ns['prefix']), // namespace url
+				$csvText(implode(', ', [ $acl->getID(), $acl->getName(), $acl->getRawLabel() ])), // Keywords
+				$csvText($acl->getRawOpis()), // Abstract
+				'EPSG:4326', // SRS
+				"8.12328509871721", // LatLongBoundingBox - minx
+				"38.8575126897477", // LatLongBoundingBox - miny
+				"9.838674658246807", // LatLongBoundingBox - maxx
+				"41.31378404137082", // LatLongBoundingBox - maxy
+			]);
+		}, $aclList));
+		echo $csvLineSepartor;
+
+		echo implode($csvLineSepartor, array_map(function ($typeName) use ($csvText, $csvValueSepartor) {
+			list($prefix, $name) = explode(':', $typeName);
+			return implode($csvValueSepartor, [
+				"p5_{$prefix}:{$name}", // Name
+				$csvText($name), // Title
+				Api_WfsNs::getNsUri($prefix), // namespace url
+				$csvText($name), // Keywords
+				$csvText($name), // Abstract
+				'EPSG:4326', // SRS
+				"8.12328509871721", // LatLongBoundingBox - minx
+				"38.8575126897477", // LatLongBoundingBox - miny
+				"9.838674658246807", // LatLongBoundingBox - maxx
+				"41.31378404137082", // LatLongBoundingBox - maxy
+			]);
+		}, Core_AclHelper::getCustomAclList()));
+		exit;
+	}
+
+	static function sendGetCapabilitiesXml($wpsServerUrl, $serviceTitle, $serviceDescription, $aclList) {
+		throw new Api_WfsException("Not Implemented sendGetCapabilitiesXml for Wps version 1.0.0", 501);
+		header('Content-type: application/xml; charset=utf-8');
+		$xmlWriter = new Core_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('wps:Capabilities');
+		$xmlWriter->writeAttribute('service', "WPS");
+		$xmlWriter->writeAttribute('version', "2.0.0");
+		// $xmlWriter->writeAttribute('xml:lang', "en-GB");
+		$xmlWriter->writeAttribute('xmlns:xlink', "http://www.w3.org/1999/xlink");
+		$xmlWriter->writeAttribute('xmlns:wps', "http://www.opengis.net/wps/1.0.0");
+		$xmlWriter->writeAttribute('xmlns:ows', "http://www.opengis.net/ows/1.1");
+		$xmlWriter->writeAttribute('xmlns:ogc', "http://www.opengis.net/ogc");
+		$xmlWriter->writeAttribute('xmlns:xsi', "http://www.w3.org/2001/XMLSchema-instance");
+		// $xmlWriter->writeAttribute('xsi:schemaLocation', "http://www.opengis.net/wps/1.0.0 ../wpsGetCapabilities_response.xsd");
+		$xmlWriter->writeAttribute('updateSequence', "1");
+
+		// $xmlWriter->writeAttribute('xmlns', 'http://www.opengis.net/wfs');
+		// $xmlWriter->writeAttribute('xmlns:ogc', 'http://www.opengis.net/ogc');
+		// $xmlWriter->writeAttribute('xmlns:xsi', 'http://www.w3.org/2001/XMLSchema-instance');
+		foreach (Api_WfsNs::getNsList() as $uri => $prefix) {
+			$xmlWriter->writeAttribute("xmlns:{$prefix}", $uri);
+		}
+		$schemaLocations = [];
+		//$schemaLocations[] = 'http://www.opengis.net/wfs http://webgis.regione.sardegna.it:80/geoserver/schemas/wfs/1.0.0/WFS-capabilities.xsd';// @from http://webgis.regione.sardegna.it/geoserver/ows?service=WFS&request=GetCapabilities
+		if (!empty($schemaLocations)) $xmlWriter->writeAttribute('xsi:schemaLocation', implode(' ', $schemaLocations));
+		$xmlWriter->h('ows:ServiceIdentification', [
+			['ows:Title', $serviceTitle],
+			['ows:Abstract', $serviceDescription],
+			['ows:Keywords', [
+				['ows:Keyword', "WPS"],
+			] ],
+			['ows:ServiceType', "WPS"],
+			['ows:ServiceTypeVersion', "2.0.0"],
+			['ows:Fees', "NONE"],
+			['ows:AccessConstraints', "NONE"],
+		]);
+		// 	<ows:ServiceProvider>
+		// 		<ows:ProviderName>Agriculture and Agri-Food Canada</ows:ProviderName>
+		// 		<ows:ProviderSite xlink:href="http://gis.agr.gc.ca/"/>
+		// 		<ows:ServiceContact>
+		// 			<ows:IndividualName>Peter Schut</ows:IndividualName>
+		// 			<ows:PositionName>Information System Scientist</ows:PositionName>
+		// 			<ows:ContactInfo>
+		// 				<ows:Phone>
+		// 					<ows:Voice>+1 613 759-1874</ows:Voice>
+		// 					<ows:Facsimile>+1 613 759-1937</ows:Facsimile>
+		// 				</ows:Phone>
+		// 				<ows:Address>
+		// 					<ows:DeliveryPoint>Room 1135, Neatby Building, 960, Carling Avenue</ows:DeliveryPoint>
+		// 					<ows:City>Ottawa</ows:City>
+		// 					<ows:AdministrativeArea>ON</ows:AdministrativeArea>
+		// 					<ows:PostalCode>K1AOC6</ows:PostalCode>
+		// 					<ows:Country>Canada</ows:Country>
+		// 					<ows:ElectronicMailAddress>schutp@agr.gc.ca</ows:ElectronicMailAddress>
+		// 				</ows:Address>
+		// 			</ows:ContactInfo>
+		// 		</ows:ServiceContact>
+		// 	</ows:ServiceProvider>
+		// $xmlWriter->h('ows:ServiceProvider', [
+		// 	[ 'ows:ProviderName', "" ], // TODO: company name - from config?
+		// 	[ 'ows:ProviderSite', [ 'xlink:href' => $wpsServerUrl ], null ],
+		// 	// [ 'ows:ServiceContact', [
+		// 	// 	[ 'ows:IndividualName', "..." ],
+		// 	// ] ],
+		// ]);
+		//
+		// $xmlWriter->h('ows:OperationsMetadata', [
+		// 	[ 'ows:Operation', [ 'name' => "GetCapabilities" ], [
+		// 		[ 'ows:DCP', [
+		// 			[ 'ows:HTTP', [
+		// 				[ 'ows:Get', [ 'xlink:href' => $wpsServerUrl ], null ],
+		// 			] ]
+		// 		] ]
+		// 	] ],
+		// 	[ 'ows:Operation', [ 'name' => "DescribeProcess" ], [
+		// 		[ 'ows:DCP', [
+		// 			[ 'ows:HTTP', [
+		// 				[ 'ows:Get', [ 'xlink:href' => $wpsServerUrl ], null ],
+		// 				[ 'ows:Post', [ 'xlink:href' => $wpsServerUrl ], null ],
+		// 			] ]
+		// 		] ]
+		// 	] ],
+		// 	[ 'ows:Operation', [ 'name' => "Execute" ], [
+		// 		[ 'ows:DCP', [
+		// 			[ 'ows:HTTP', [
+		// 				[ 'ows:Get', [ 'xlink:href' => $wpsServerUrl ], null ],
+		// 				[ 'ows:Post', [ 'xlink:href' => $wpsServerUrl ], null ],
+		// 			] ]
+		// 		] ]
+		// 	] ],
+		// 	[ 'ows:Operation', [ 'name' => "GetStatus" ], [
+		// 		[ 'ows:DCP', [
+		// 			[ 'ows:HTTP', [
+		// 				[ 'ows:Get', [ 'xlink:href' => $wpsServerUrl ], null ],
+		// 				[ 'ows:Post', [ 'xlink:href' => $wpsServerUrl ], null ],
+		// 			] ]
+		// 		] ]
+		// 	] ],
+		// 	[ 'ows:Operation', [ 'name' => "GetResult" ], [
+		// 		[ 'ows:DCP', [
+		// 			[ 'ows:HTTP', [
+		// 				[ 'ows:Get', [ 'xlink:href' => $wpsServerUrl ], null ],
+		// 				[ 'ows:Post', [ 'xlink:href' => $wpsServerUrl ], null ],
+		// 			] ]
+		// 		] ]
+		// 	] ],
+		// 	[ 'ows:Operation', [ 'name' => "Dismiss" ], [
+		// 		[ 'ows:DCP', [
+		// 			[ 'ows:HTTP', [
+		// 				[ 'ows:Get', [ 'xlink:href' => $wpsServerUrl ], null ],
+		// 				[ 'ows:Post', [ 'xlink:href' => $wpsServerUrl ], null ],
+		// 			] ]
+		// 		] ]
+		// 	] ],
+		// ]);
+		// $xmlWriter->h('wps:ProcessOfferings', [ // TODO:? for version 1.0.0 ?
+		// 	[ 'wps:Process', [ 'wps:processVersion' => "1" ], [
+		// 		[ 'ows:Identifier', "buffer" ],
+		// 		[ 'ows:Title', "Buffer a polygon feature" ],
+		// 		[ 'ows:Abstract', "Buffer the polygon coordinates found in one GML stream by a given buffer distance, and output the results in GML." ],
+		// 		[ 'ows:Metadata', [ 'xlink:title' => "buffer" ], null ],
+		// 		[ 'ows:Metadata', [ 'xlink:title' => "polygon" ], null ],
+		// 	] ]
+		// ]);
+		// $xmlWriter->h('wps:Languages', [
+		// 	[ 'wps:Default', [
+		// 		[ 'ows:Language', "en-CA" ],
+		// 	] ],
+		// 	[ 'wps:Supported', [
+		// 		[ 'ows:Language', "pl-PL" ],
+		// 	] ]
+		// ]);
+		$xmlWriter->h('wps:Contents', [
+			[ 'wps:ProcessSummary', [ 'jobControlOptions' => "sync-execute async-execute dismiss" ], [
+				[ 'ows:Title', "example 1" ],
+				[ 'ows:Identifier', "{$wpsServerUrl}/task/example1" ],
+			] ],
+			[ 'wps:ProcessSummary', [ 'jobControlOptions' => "async-execute dismiss", 'processVersion' => "1.4.0" ], [
+				[ 'ows:Title', "example 2" ],
+				[ 'ows:Identifier', "{$wpsServerUrl}/task/example2" ],
+			] ],
+		]);
+		$xmlWriter->h('wps:WSDL', [ 'xlink:href' => "http://foo.bar/wps?WSDL" ], null);
+
+		$xmlWriter->endElement();// WFS_Capabilities
+		$xmlWriter->endDocument();
+		exit;
+	}
+
+}

+ 2 - 1
SE/se-lib/Api/WsdlServer.php

@@ -1,8 +1,9 @@
 <?php
-
 // https://biuro.biall-net.pl/dev-pl/se-master/wfs-data.php/wsdl
 // https://biuro.biall-net.pl/dev-pl/se-master/wfs-data.php/wsdl/wfs-http-bindings.wsdl
 
+Lib::loadClass('Api_WfsServerBase');
+
 /*
   Types - a container for data type definitions using some type system (such as XSD).
   Message - an abstract, typed definition of the data being communicated.

+ 72 - 0
SE/wps.php

@@ -0,0 +1,72 @@
+<?php
+
+/* QGIS- reverse inginiering:
+	?SERVICE=WFS&REQUEST=GetCapabilities&VERSION=1.0.0
+ */
+
+require_once dirname(__FILE__) . '/se-lib/bootstrap.php';
+
+if (!Request::isHttps()) {
+	header("Location: https://{$_SERVER['HTTP_HOST']}{$_SERVER['REQUEST_URI']}");
+	exit();
+}
+
+date_default_timezone_set('Europe/Warsaw');// PHP 5 >= 5.1.0 required by date functions
+
+$errorReportingLevel = E_ALL & ~E_NOTICE;
+error_reporting($errorReportingLevel);
+ini_set('error_reporting', $errorReportingLevel);
+
+trigger_error("WPS: {$_SERVER['REQUEST_METHOD']} https://{$_SERVER['HTTP_HOST']}{$_SERVER['REQUEST_URI']}", E_USER_NOTICE); // TODO: RMMR DBG
+if ('POST' === $_SERVER['REQUEST_METHOD']) {
+	trigger_error("WPS POST BODY: " . Request::getRequestBody(), E_USER_NOTICE); // TODO: RMMR DBG
+}
+
+if (file_exists(APP_PATH_ROOT . "/config/.config_{$_SERVER['SERVER_NAME']}.php")) {
+	require APP_PATH_ROOT . "/config/.config_{$_SERVER['SERVER_NAME']}.php";
+}
+if (file_exists(APP_PATH_ROOT . "/.config.php")) include APP_PATH_ROOT . "/.config.php";
+
+require_once APP_PATH_ROOT . "/superedit-SEF.php";
+SEF('DEBUG_S');
+
+Lib::loadClass('ApiUser');
+Lib::loadClass('Api');
+
+session_start();
+session_write_close();
+
+$apiUser = new ApiUser();
+// ?LOGIN=LOGOUT
+if ('LOGOUT' == V::get('LOGIN', '', $_GET)) {
+	$apiUser->logout();
+} else {
+	$apiUser->auth();
+}
+
+set_time_limit(5 * 60);
+
+$taskPath = Request::getRewriteTaskPath();
+$taskPath = "/xml/wps{$taskPath}";
+IF(V::get('DBG','',$_GET)){echo'<pre style="max-height:200px;overflow:auto;border:1px solid red;text-align:left;">taskPath (' . __CLASS__ . '::' . __FUNCTION__ . ':' . __LINE__ . '): ';print_r($taskPath);echo'</pre>';}
+if ('/xml/wfs' == substr($taskPath, 0, 8)) {
+	$taskPath = "/xml/wfsQgis/" . substr($taskPath, 9);
+}
+
+$api = new Api();
+$api->setUser($apiUser);
+$apiBaseUri = Request::getScriptUri();
+$api->setBaseUri($apiBaseUri);// TODO: RMME - replaced with Api_WfsNs::getBaseWfsUri();
+try {
+	$api->execute($taskPath);
+}
+catch (HttpException $e) {
+	Http::sendHeaderByCode($e->getCode());
+	echo $e->getMessage();
+}
+catch (Exception $e) {
+	Http::sendHeaderByCode(500);
+	echo $e->getMessage();
+}
+
+?>

Certains fichiers n'ont pas été affichés car il y a eu trop de fichiers modifiés dans ce diff