$value) $lowerArgs[ strtolower($name) ] = trim($value); $args['xsd:type'] = V::get('typename', '', $lowerArgs); $exType = explode(':', $args['xsd:type']); if (count($exType) != 2) throw new HttpException("Wrong param TYPENAME", 400); $args['typePrefix'] = $exType[0]; $args['typeName'] = $exType[1]; $args['srsname'] = V::get('SRSNAME', '', $lowerArgs);// eg. EPSG:4326 $args['limit'] = V::get('maxfeatures', $args['limit'], $lowerArgs, 'int'); $args['limit'] = V::get('count', $args['limit'], $lowerArgs, 'int'); $defaultFeaturesLimit = ('biuro.biall-net.pl' == V::get('SERVER_NAME', '', $_SERVER)) ? 50000 : 10000; if ($args['limit'] <= 0) $args['limit'] = $defaultFeaturesLimit;// default limit $args['offset'] = V::get('startindex', 0, $lowerArgs, 'int'); $args['ogc:filter'] = urldecode(V::get('filter', '', $lowerArgs)); if (empty($args['ogc:filter'])) {// read ogc:Filter from POST body if not defined in GET $reqBody = Request::getRequestBody(); if (!empty($reqBody)) { $parsedRequest = self::parseOgcFilterRequest($reqBody); DBG::log($parsedRequest, 'array', 'parsed ogc query request'); if (!empty($parsedRequest['ogc:Filter'])) $args['ogc:filter'] = $parsedRequest['ogc:Filter']; if (!empty($parsedRequest['wfs:PropertyName'])) { $args['filterFields'] = array_merge($args['filterFields'], $parsedRequest['wfs:PropertyName']); } } } if (empty($args['filterFields']) && $args['resolve'] && $args['resolveDepth'] > 0) { $args['filterFields'][] = '*' . str_repeat("/*", $args['resolveDepth'] - 1); } $args['sortBy'] = V::get('sortby', '', $lowerArgs);// TODO: split to array of array(fieldName, (asc | desc)) $args['wfs:propertyName'] = trim(V::get('propertyname', '', $lowerArgs)); if (strlen($args['wfs:propertyName']) > 0) { $exFields = explode(',', $args['wfs:propertyName']); $exFields = array_map('trim', $exFields); $exFields = array_filter($exFields, [ 'V', 'filterNotEmpty' ]); $args['filterFields'] = array_merge($args['filterFields'], $exFields); } $args['resultType'] = V::get('resulttype', '', $lowerArgs); $args['bbox'] = V::get('bbox', '', $lowerArgs); if (!empty($args['bbox'])) { // BBOX may have EPSG at then end - example: ",EPSG:4326" $num = "\d+.?\d*?";// "\d+(.\d+)?" if (!preg_match("/^({$num}),({$num}),({$num}),({$num})(\,EPSG:\d+)?$/", $args['bbox'], $matches)) throw new Exception("Illegal BBOX format"); // QGIS send BBOX in correct order: 54.23580872176457,18.46844302390853,54.25220902538883,18.492990600812696 // first number should not be smaller then second // example $matches: // [0] => 18.492990600812696,54.23580872176457,18.46844302390853,54.25220902538883 // [1] => 18.492990600812696 // [2] => 54.23580872176457 // [3] => 18.46844302390853 // [4] => 54.25220902538883 // (optional) EPGS $bboxPoints = ($matches[1] > $matches[2]) ? [ $matches[1], $matches[2], $matches[3], $matches[4] ] : [ $matches[2], $matches[3], $matches[4], $matches[1] ]; $args['bbox'] = implode(",", $bboxPoints); } $args['wfs:featureID'] = V::get('featureid', null, $lowerArgs);// TODO: allow multiply feature id (csv) if ($args['wfs:featureID']) { $dotPos = strpos($args['wfs:featureID'], '.'); if (!$dotPos) throw new Exception("Wrong param featureID"); if ($args['typeName'] != substr($args['wfs:featureID'], 0, $dotPos)) throw new Exception("Wrong typeName in param featureID"); $args['primaryKey'] = substr($args['wfs:featureID'], $dotPos + 1); } $pk = V::get('primarykey', '', $lowerArgs); if ($pk) { $args['primaryKey'] = (false !== strpos($pk, ',')) ? explode(',', $pk) : $pk; } if(DBG::isActive() && V::get('DBG', 0, $_GET)){ echo "\$lowerArgs:";print_r($lowerArgs); } if(DBG::isActive() && V::get('DBG', 0, $_GET)){ echo "\$args:";print_r($args); } return $args; } public static function parseOgcFilterRequest($requestOgcFilter) { // GetFeature: @maxFeatures, @traverseXlinkDepth, @traverseXlinkExpiry // \-- (1..) wfs:Query: @typeName // \--- (0..) ---: wfs:PropertyName // : wfs:XlinkPropertyName // : ogc:Function // ogc:Filter // ogc:SortBy // \--- (1..) ogc:SortProperty // \---: ogc:PropertyName // : ogc:SortOrder ( DESC / ASC ) // // // ASTA // ASC // // if (empty($requestOgcFilter)) return ''; $requestXml = new DOMDocument(); if (!$requestXml->loadXml($requestOgcFilter)) { throw new Exception("Parse ogc query failed"); } $rootNode = $requestXml->documentElement; // if ($rootNode->getAttribute('resolve')) DBG::log([$rootNode->getAttribute('resolve'), $rootNode->getAttribute('resolveDepth')], 'array', "TODO: use wfs:GetFeature @resolve, @resolveDepth"); $nodesQuery = []; foreach ($requestXml->getElementsByTagNameNS('http://www.opengis.net/wfs', 'Query') as $element) { DBG::log($element->nodeName, 'array', "main loop - wfs:Query"); $nodesQuery[] = $element; } if (empty($nodesQuery)) { // legacy - try to find 'ogc:Filter' $tagsFilter = []; foreach ($requestXml->getElementsByTagNameNS('http://www.opengis.net/ogc', 'Filter') as $element) { DBG::log($element->nodeName, 'array', "loop element (0 * wfs:Query)"); $tagsFilter[] = $requestXml->saveXML($element); } DBG::log($tagsFilter, 'array', "\$tagsFilter (0 * wfs:Query)"); return [ 'ogc:Filter' => (!empty($tagsFilter)) ? reset($tagsFilter) // TODO: only one ogc:Filter allowed : '' ]; } if (1 === count($nodesQuery)) { $tagsFilter = []; foreach ($requestXml->getElementsByTagNameNS('http://www.opengis.net/ogc', 'Filter') as $element) { // DBG::log($element->nodeName, 'array', "loop ogc:Filter (1 * wfs:Query)"); $tagsFilter[] = $requestXml->saveXML($element); } DBG::log($tagsFilter, 'array', "\$tagsFilter (1 * wfs:Query)"); $tagsWfsPropertyName = []; foreach ($requestXml->getElementsByTagNameNS('http://www.opengis.net/wfs', 'PropertyName') as $element) { // DBG::log($element->nodeValue, 'array', "loop wfs:PropertyName (1 * wfs:Query)"); if ($element->getAttribute('resolve')) DBG::log([$element->getAttribute('resolve'), $element->getAttribute('resolveDepth'), $element->getAttribute('resolvePath')], 'array', "TODO: use wfs:PropertyName @resolve, @resolveDepth, @resolvePath"); $value = $element->nodeValue; if (in_array($element->getAttribute('resolve'), ['all', 'local', 'remote'])) { $depth = $element->getAttribute('resolveDepth'); if ('*' !== substr($value, -1)) { // TODO: propertyName is not regex if ('*' === $depth) $value .= "/**"; // TODO: resolveDepth="*" - resolve all else if ((int)$depth > 0) $value .= str_repeat("/*", $depth); } } $tagsWfsPropertyName[] = $value; } DBG::log($tagsWfsPropertyName, 'array', "\$tagsWfsPropertyName (1 * wfs:Query)"); return array_filter([ 'ogc:Filter' => (!empty($tagsFilter)) ? reset($tagsFilter) : '', 'wfs:PropertyName' => (!empty($tagsWfsPropertyName)) ? $tagsWfsPropertyName : '', ], function ($value) { return !empty($value); }); } throw new Exception("Not imeplemented multiple ogc:Query"); // multiple ogc:Query require ogc:Query/@typeName } public static function convertOgcPropertyListToFeatureQueryCols(&$schemaCache, $ogcPropertyList, $acl, $isRoot = false) { return self::convertOgcPropsRecurse($schemaCache, $ogcPropertyList, $acl, $isRoot, $dbgLoopNr = 0, $dbgXpath = $acl->getNamespace()); } public static function convertOgcPropsRecurse(&$schemaCache, $ogcPropertyList, $aclOrSchema, $isRoot = false, $dbgLoopNr = 0, $dbgXpath = '') { if ($dbgLoopNr > 10) { DBG::log($ogcPropertyList, 'array', 'convertOgcPropsRecurse: LOOP LIMIT 10! - return []'); return []; } $acl = null; if (is_array($aclOrSchema) && !empty($aclOrSchema['namespace'])) { $acl = Core_AclHelper::getAclByNamespace($aclOrSchema['namespace'], false, $aclOrSchema); } else if ($aclOrSchema instanceof Core_AclBase) { $acl = $aclOrSchema; } else throw new Exception("Missing acl"); if (empty($ogcPropertyList)) { $ogcPropertyList = array_values($acl->getFieldListByIdZasob()); $ogcPropertyList = array_filter($ogcPropertyList, function ($fieldName) use ($acl, $isRoot) { return ($isRoot || $acl->canReadField($fieldName)); }); } $aclFields = array_filter($ogcPropertyList, function ($prop) { return ( false === strpos($prop, '/') ); }); $nestedFields = array_reduce( array_filter($ogcPropertyList, function ($prop) { return ( false !== strpos($prop, '/') ); }), function ($ret, $propNested) { list($childName, $nestedPart) = explode('/', $propNested, 2); if (!array_key_exists($childName, $ret)) $ret[ $childName ] = []; $ret[ $childName ][] = $nestedPart; return $ret; }, [] ); if (!empty($nestedFields)) { if (array_key_exists('*', $nestedFields)) { // add missing local fields if xpath like '*/...' $aclFields[] = '*'; } } if (!empty($nestedFields)) { // add nested part to refs if xpath like '*/...' if (array_key_exists('*', $nestedFields)) { $nestedParts = $nestedFields['*']; unset($nestedFields['*']); DBG::log($nestedParts, 'array', "convertOgcPropsRecurse: '*' in \$nestedFields - \$nestedParts ns({$dbgXpath})"); $canReadRefs = array_values($acl->getFieldListByIdZasob()); $canReadRefs = array_filter($canReadRefs, function ($fieldName) use ($acl, $isRoot) { return (false !== strpos($fieldName, ":") && ($isRoot || $acl->canReadField($fieldName))); }); foreach ($canReadRefs as $refField) { foreach ($nestedParts as $nestedPart) { $nestedFields[ $refField ][] = $nestedPart; } } } } if (!empty($nestedFields)) { $aclFields = array_unique(array_merge($aclFields, array_keys($nestedFields))); } if (in_array('*', $aclFields)) { $aclFields = array_filter($aclFields, function ($fieldName) { return ( '*' !== $fieldName); }); $allAclFields = array_values($acl->getFieldListByIdZasob()); $allAclFields = array_filter($allAclFields, function ($fieldName) use ($acl, $isRoot) { return ($isRoot || $acl->canReadField($fieldName)); }); if ($allAclFields) $aclFields = array_unique(array_merge($aclFields, $allAclFields)); } DBG::log([$aclFields, $nestedFields, $acl->getFieldListByIdZasob()], 'array', "convertOgcPropsRecurse: splited to acl fields and nested fields ns({$dbgXpath})"); foreach ($aclFields as $fieldName) { if (!$isRoot && !$acl->canReadField($fieldName)) throw new Exception("Access Denied to read field '{$fieldName}' from '" . $acl->getNamespace() . "'"); } foreach ($aclFields as $fieldName) { if (false !== strpos($fieldName, ':')) { $childNs = str_replace(['__x3A__', ':'], '/', $fieldName); $schemaCache[$childNs] = SchemaFactory::loadDefaultObject('SystemObject')->getItem($childNs, [ 'propertyName' => '*,field' ]); } } $contextFieldList = $aclFields; foreach ($nestedFields as $childName => $nestedProps) { $childNs = str_replace(['__x3A__', ':'], '/', $childName); if (!array_key_exists($childNs, $schemaCache)) { $schemaCache[$childNs] = SchemaFactory::loadDefaultObject('SystemObject')->getItem($childNs, [ 'propertyName' => '*,field' ]); } $childCtxFields = array_map(function ($childCtxFld) use ($childName) { return "{$childName}/{$childCtxFld}"; }, self::convertOgcPropsRecurse($schemaCache, $nestedProps, $schemaCache[$childNs], $dbgLoopNr + 1, "{$dbgXpath}/{$childName}")); DBG::log([ $contextFieldList, $childCtxFields ], 'array', "convertOgcPropsRecurse: array merge ns({$dbgXpath})"); $contextFieldList = array_merge( $contextFieldList, $childCtxFields ); DBG::log($contextFieldList, 'array', "convertOgcPropsRecurse: array merged ns({$dbgXpath})"); } DBG::log($contextFieldList, 'array', "convertOgcPropsRecurse: return \$contextFieldList ns({$dbgXpath})"); return $contextFieldList; } // TODO: add $contextAcl and context xpath to check for special perms by contextAcl /** @example: * Api_Wfs_GetFeature::printXmlFeatureRecurse($xmlWriter, $acl, $item, [ * 'fields' => $searchParams['cols'], * 'tagName' => "{$wfsNs}:{$type}", * 'showAdvancedAttrs' => !$simple, * 'xsdAttributes' => array_merge( * [ 'fid' => "{$type}.{$itemKey}" ], * (!$simple) * ? [ "{$rootWfsNs}:web_link" => Request::getPathUri() . "index.php?_route=ViewTableAjax&namespace=" . $acl->getNamespace() . "#EDIT/{$itemKey}" ] * : [] * ) * ], $schemaCache, $printedFidLog); */ public static function printXmlFeatureRecurse($xmlWriter, $acl, $item, $params = [], $schemaCache = [], $printedFidLog = []) { $showFields = V::get('fields', [], $params, 'array'); // TODO: if empty $showFields ? $tagName = V::get('tagName', '', $params); $attrs = V::get('xsdAttributes', [], $params, 'array'); $showAdvancedAttrs = V::get('showAdvancedAttrs', false, $params, 'bool'); $dbgFid = V::get('fid', 0, $attrs); $outputBlobFormat = V::get('outputBlobFormat', '', $params, 'word'); if(V::get('DBG_XML', '', $_GET))$xmlWriter->writeComment("DBG: print Xml Feature Recurse... '{$tagName}'" . ( $dbgFid ? " fid='{$dbgFid}'" : "" )); // TODO: DBG // DBG::log($acl, 'array', "DBG: print Xml Feature Recurse( ... {$tagName}, \$acl)" . ( $dbgFid ? " fid='{$dbgFid}'" : "" ) . " \$acl"); DBG::log($item, 'array', "DBG: print Xml Feature Recurse( ... {$tagName}, \$item)" . ( $dbgFid ? " fid='{$dbgFid}'" : "" ) . " \$item"); DBG::log($showFields, 'array', "DBG: print Xml Feature Recurse( ... {$tagName}, \$item)" . ( $dbgFid ? " fid='{$dbgFid}'" : "" ) . " \$showFields"); DBG::log([$attrs, $showAdvancedAttrs, array_keys($schemaCache), $printedFidLog], 'array', "DBG: print Xml Feature Recurse( ... {$tagName}, \$attrs, \$showAdvancedAttrs, keys(\$schemaCache), \$printedFidLog)"); if ($dbgFid) { if (in_array($dbgFid, $printedFidLog)) { DBG::log("TODO: in_array({$dbgFid}, \$printedFidLog)"); } } if ($dbgFid) $printedFidLog[] = $dbgFid; // $rootWfsNs = 'p5'; list($itemPrefix, $localName) = explode(':', $tagName); if (1 === count($item) && !empty($item['xlink'])) { // @example 'xlink' => 'https://biuro.biall-net.pl/wfs/default_db/CRM_PROCES#PROCES.857' $xlink = $item['xlink']; list($xlinkUrl, $xlinkFid) = explode('#', $xlink); DBG::log($item[$fldName], 'array', "xlinks for '{$tagName}'"); $xmlWriter->startElement($tagName); foreach ($attrs as $name => $value) { $xmlWriter->writeAttribute($name, $value); } if ($showAdvancedAttrs && !$acl->canReadObjectField($fldName, (object)$item)) { $xmlWriter->writeAttribute("p5:allow_read", "false"); } if ($showAdvancedAttrs && $acl->canWriteObjectField($fldName, (object)$item)) { $xmlWriter->writeAttribute("p5:allow_write", "true"); } $xmlWriter->writeAttribute('xlink:href', $xlink); $xmlWriter->endElement();// {$itemPrefix}:{$fldName} return; } if (1 === count($item) && !empty($item['p5:links'])) { DBG::log($item, 'array', "DBG p5:links"); // array ( // 'p5:links' => // array ( // 'p5:next' => // array ( // '@typeName' => 'default_db__x3A__CRM_WSKAZNIK:CRM_WSKAZNIK', // '@backRefPK' => '6125', // ), // ), // ) $xmlWriter->startElement('p5:links'); foreach ($item['p5:links'] as $type => $link) { if ('p5:next' === $type) { $xmlWriter->startElement('p5:next'); if (empty($link['@typeName'])) throw new Exception("Missing 'p5:links/p5:next/@typeName'"); if (empty($link['@backRefNS'])) throw new Exception("Missing 'p5:links/p5:next/@backRefNS'"); if (empty($link['@backRefPK'])) throw new Exception("Missing 'p5:links/p5:next/@backRefPK'"); if (empty($link['@startIndex'])) throw new Exception("Missing 'p5:links/p5:next/@startIndex'"); if (empty($link['value'])) throw new Exception("Missing 'p5:links/p5:next'"); $xmlWriter->writeAttribute("p5:typeName", $link['@typeName']); $xmlWriter->writeAttribute("p5:backRefNS", $link['@backRefNS']); $xmlWriter->writeAttribute("p5:backRefPK", $link['@backRefPK']); $xmlWriter->writeAttribute("p5:startIndex", $link['@startIndex']); $xmlWriter->text($link['value']); // str_replace('&', '&', $link['value']) $xmlWriter->endElement(); // 'p5:next' } else { DBG::log("TODO: Not Implemented p5:links chldren '{$type}'"); $xmlWriter->writeComment("TODO: Not implemented p5:links children '{$type}'"); } } $xmlWriter->endElement(); // 'p5:links' return; } $xmlWriter->startElement($tagName); foreach ($attrs as $name => $value) { $xmlWriter->writeAttribute($name, $value); } // $fldList = $acl->getRealFieldListByIdZasob(); $fldList = $acl->getFieldListByIdZasob(); $geomFld = null; foreach ($fldList as $fldName) { if ($acl->isGeomField($fldName)) { $geomFld = $fldName; } } DBG::log($fldList, 'array', ">>> loop start fields(".count($fldList).")"); // DBG::log($showFields, 'array', "DBG: \$showLocalFields \$showFields 0"); $showLocalFields = ($showFields) // if empty filter cols show all local fields ? array_filter($showFields, function ($showFieldName) { return (false === strpos($showFieldName, "/")); }) : $fldList; DBG::log($showLocalFields, 'array', "DBG: \$showLocalFields"); $fldList = array_filter($fldList, function ($fieldName) use ($showLocalFields) { return (in_array($fieldName, $showLocalFields)); }); DBG::log($fldList, 'array', ">>> loop start filtered fields(".count($fldList).")"); foreach ($fldList as $idZasob => $fldName) { DBG::log(">>> loop {$idZasob} => {$fldName}..."); $fldType = $acl->getXsdFieldType($fldName); DBG::log(">>> loop '{$fldName}' xsdType: '{$fldType}'"); if (!$acl->canReadObjectField($fldName, (object)$item)) if(V::get('DBG_XML', '', $_GET))$xmlWriter->writeComment("DBG: skip - !canReadObjectField('{$fldName}')"); // TODO: DBG if (!$acl->canReadObjectField($fldName, (object)$item)) continue; DBG::log(">>> loop '{$fldName}' can read..."); if ($geomFld != null && $fldName == $geomFld) { $xmlWriter->startElement("{$itemPrefix}:{$fldName}"); if ($showAdvancedAttrs && !$acl->canReadObjectField($fldName, (object)$item)) { $xmlWriter->writeAttribute("p5:allow_read", "false"); } if ($showAdvancedAttrs && $acl->canWriteObjectField($fldName, (object)$item)) { $xmlWriter->writeAttribute("p5:allow_write", "true"); } (new Api_WfsGeomTypeConverter())->createGmlFromWkt_xmlWriter($item[$fldName], $xmlWriter); $xmlWriter->endElement();// {$itemPrefix}:{$fldName} } else if (is_array($item[$fldName])) {// TODO: by struct - REF field DBG::log($item[$fldName], 'array', ">>> loop({$itemKey}) REF item[{$itemKey}][{$fldName}]"); if (empty($item[$fldName])) { // SKIP empty fields if(V::get('DBG_XML', '', $_GET))$xmlWriter->writeComment("DBG: skip empty field '{$fldName}'"); // TODO: DBG // $xmlWriter->h($fldName); } else { if(V::get('DBG_XML', '', $_GET))$xmlWriter->writeComment("DBG: TODO: array field... '{$fldName}'"); // TODO: DBG // $xmlWriter->writeComment("TODO: ".$acl->getName().".{$itemKey}/{$fldName} ..."); $fieldNs = str_replace(['__x3A__', ':'], '/', $fldName); // substr($xsdType, 4)); if (!array_key_exists($fieldNs, $schemaCache)) { // maybe only xlinks - acl not needed $firstItem = reset($item[$fldName]); if (1 === count($firstItem) && !empty($firstItem['xlink'])) { foreach ($item[$fldName] as $childItem) { // xlink or p5:links self::printXmlFeatureRecurse($xmlWriter, $childAcl = null, $childItem, [ 'fields' => [], 'tagName' => $fldName, 'xsdAttributes' => [], 'showAdvancedAttrs' => $showAdvancedAttrs, 'outputBlobFormat' => $outputBlobFormat, ], $schemaCache, $printedFidLog); } } else { DBG::log($schemaCache, 'array', "Error Processing Request - field is not ref or missing acl ".$acl->getName().".{$itemKey}/{$fldName}"); if(V::get('DBG_XML', '', $_GET))$xmlWriter->writeComment("Error Processing Request - field is not ref or missing acl ".$acl->getName().".{$itemKey}/{$fldName}"); } } else { DBG::log($schemaCache[$fieldNs], 'array', "fetch child acl ".$acl->getName().".{$itemKey}/{$fldName}"); $childAcl = Core_AclHelper::getAclByNamespace($schemaCache[$fieldNs]['namespace'], false, $schemaCache[$fieldNs]); $childName = $schemaCache[$fieldNs]['name']; foreach ($item[$fldName] as $childItem) { // DBG::log($showFields, 'array', "DBG: fld({$fldName}) \$showFields 0"); $showChildFields = array_filter($showFields, function ($showFieldName) use ($fldName) { return ("{$fldName}/" === substr("{$showFieldName}", 0, strlen($fldName) + 1)); }); // DBG::log($showChildFields, 'array', "DBG: fld({$fldName}) \$showChildFields 1"); $showChildFields = array_map(function ($showFieldName) use ($fldName) { return substr($showFieldName, strlen($fldName) + 1); }, $showChildFields); // DBG::log($showChildFields, 'array', "DBG: fld({$fldName}) \$showChildFields 2"); $childPK = V::get($childAcl->getPrimaryKeyField(), '', $childItem); self::printXmlFeatureRecurse($xmlWriter, $childAcl, $childItem, [ 'fields' => $showChildFields, 'tagName' => $fldName, 'xsdAttributes' => ($childPK) ? [ 'fid' => "{$childName}.{$childPK}" ] : [], 'showAdvancedAttrs' => $showAdvancedAttrs, 'outputBlobFormat' => $outputBlobFormat, ], $schemaCache, $printedFidLog); } // foreach ($item[$fldName] as $refItem) { // DBG::log($refItem, 'array', "\$refItem fld({$fldName})"); // if (1 == count($refItem) && !empty($refItem['xlink'])) { // $xmlWriter->startElement($schemaCache[$fieldNs]['typeName']); // $xmlWriter->writeAttribute("xlink:href", $refItem['xlink']); // $xmlWriter->endElement(); // } else { // $xmlWriter->writeComment("DBG: array field ref ... '{$fldName}'"); // TODO: DBG // $xmlWriter->startElement($schemaCache[$fieldNs]['typeName']); // foreach ($schemaCache[$fieldNs]['field'] as $field) { // if (array_key_exists($field['fieldNamespace'], $refItem)) { // $xmlWriter->writeComment("REF field ({$field['fieldNamespace']}) value({$refItem[$field['fieldNamespace']]}) TODO: get xsdType - TODO: recurse"); // DBG::log($refItem[$field['fieldNamespace']], 'array', "REF field ({$field['fieldNamespace']}) TODO: get xsdType - TODO: recurse"); // if (false !== strpos($field['fieldNamespace'], ':')) { // is ref - TODO: better check by xsdType // $xmlWriter->startElement($field['fieldNamespace']); // $xmlWriter->writeComment("TODO: recurse ..."); // // $xmlWriter->text($refItem[$field['fieldNamespace']]); // $xmlWriter->endElement(); // } else { // $xmlWriter->startElement("{$schemaCache[$fieldNs]['nsPrefix']}:{$field['fieldNamespace']}"); // $xmlWriter->text($refItem[$field['fieldNamespace']]); // $xmlWriter->endElement(); // } // } // } // $xmlWriter->endElement(); // } // } } } } else if ('xsd:base64Binary' === $acl->getXsdFieldType($fldName)) { if (empty($item[$fldName])) continue; // && '0' !== $item[$fldName] $xmlWriter->startElement("{$itemPrefix}:{$fldName}"); if ($showAdvancedAttrs && !$acl->canReadObjectField($fldName, (object)$item)) { $xmlWriter->writeAttribute("p5:allow_read", "false"); } if ($showAdvancedAttrs && $acl->canWriteObjectField($fldName, (object)$item)) { $xmlWriter->writeAttribute("p5:allow_write", "true"); } $pk = V::get($acl->getPrimaryKeyField(), '', $item); if ($showAdvancedAttrs) { $xmlWriter->writeAttribute("p5:blobUrl", Request::getPathUri() . "wfs-data.php?" . implode("&", [ "SERVICE=WFS", "VERSION=1.0.0", "REQUEST=GetBlob", "namespace=" . $acl->getNamespace(), "primaryKey={$pk}", "fieldName={$fldName}", ])); } if (in_array($item[$fldName], ['0', '1'])) { if ('base64' === $outputBlobFormat) { $content = DB::getPDO( $acl->getDatabaseID() )->getBlob( $acl->getRootTableName(), $fldName, $acl->getPrimaryKeyField(), $pk ); $xmlWriter->text(base64_encode($content)); } else if ('link' === $outputBlobFormat) { $xmlWriter->text($item[$fldName]); } else { // hide throw new Exception("Not implemented outputBlobFormat - expected base64 or link"); } } else { $xmlWriter->text(base64_encode($item[$fldName])); } $xmlWriter->endElement();// {$itemPrefix}:{$fldName} } else { $value = str_replace('&', '&', $item[$fldName]); if (empty($value) && '0' !== $value) { continue; } else { $xmlWriter->startElement("{$itemPrefix}:{$fldName}"); if ($showAdvancedAttrs && !$acl->canReadObjectField($fldName, (object)$item)) { $xmlWriter->writeAttribute("p5:allow_read", "false"); } if ($showAdvancedAttrs && $acl->canWriteObjectField($fldName, (object)$item)) { $xmlWriter->writeAttribute("p5:allow_write", "true"); } $xmlWriter->text($value); $xmlWriter->endElement();// {$itemPrefix}:{$fldName} } } } $xmlWriter->endElement(); } public static function printJsonFeatures($items, $acl, $showFields = []) { header('Content-Type: text/json; charset=UTF-8'); // TODO: only fields with Read access, then filter by $showFields list if set $outputBlobFormat = V::get('outputBlobFormat', 'base64', $_GET); if ('default_db/COMPANIES_FV' === $acl->getNamespace()) { $items = array_map(function ($item) use ($outputBlobFormat) { if (1 == $item['DOKUMENT']) { $item['DOKUMENT'] = ('base64' === $outputBlobFormat) ? base64_encode( DB::getPDO()->getBlob('COMPANIES_FV', 'DOKUMENT', 'ID', $item['ID']) ) : Request::getPathUri() . "wfs-data.php?SERVICE=WFS&VERSION=1.0.0&REQUEST=GetBlob&namespace=default_db/COMPANIES_FV&primaryKey={$item['ID']}&fieldName=DOKUMENT"; } return $item; }, $items); } echo json_encode($items); exit; } }