diff --git a/contribs/gmf/src/datasource/ExternalDataSourcesManager.js b/contribs/gmf/src/datasource/ExternalDataSourcesManager.js index 650b917762d6..da7488656b83 100644 --- a/contribs/gmf/src/datasource/ExternalDataSourcesManager.js +++ b/contribs/gmf/src/datasource/ExternalDataSourcesManager.js @@ -353,7 +353,7 @@ export class ExternalDatSourcesManager { id: id, name: layer['Title'], ogcImageType: ogcImageType, - ogcLayers: [{ + wmsLayers: [{ name: layer['Name'], queryable: queryable }], diff --git a/contribs/gmf/src/datasource/Manager.js b/contribs/gmf/src/datasource/Manager.js index 241dc8770330..7b6717dd635c 100644 --- a/contribs/gmf/src/datasource/Manager.js +++ b/contribs/gmf/src/datasource/Manager.js @@ -459,7 +459,8 @@ export class DatasourceManager { const ogcType = gmfLayer.type; let maxResolution; let minResolution; - let ogcLayers; + let wmsLayers; + let wfsLayers; let ogcServer; let wmtsLayer; let wmtsUrl; @@ -479,7 +480,13 @@ export class DatasourceManager { // OGC Layers const layers = meta.queryLayers || meta.wmsLayers; if (layers) { - ogcLayers = layers.split(',').map((layer) => { + wmsLayers = layers.split(',').map((layer) => { + return { + name: layer, + queryable: true + }; + }); + wfsLayers = layers.split(',').map((layer) => { return { maxResolution: maxResolution, minResolution: minResolution, @@ -503,7 +510,20 @@ export class DatasourceManager { minResolution = gmfLayerWMS.minResolutionHint; // OGC Layers - ogcLayers = gmfLayerWMS.childLayers.map((childLayer) => { + let queryable = false; + for (const wfslayer of gmfLayerWMS.childLayers) { + if (wfslayer.queryable) { + queryable = true; + break; + } + } + wmsLayers = gmfLayerWMS.layers.split(',').map((childLayer) => { + return { + name: childLayer, + queryable: queryable, + }; + }); + wfsLayers = gmfLayerWMS.childLayers.map((childLayer) => { return { maxResolution: childLayer.maxResolutionHint, minResolution: childLayer.minResolutionHint, @@ -584,7 +604,8 @@ export class DatasourceManager { minResolution, name, ogcImageType, - ogcLayers, + wmsLayers, + wfsLayers, ogcServerType, wfsFeatureNS, ogcType, diff --git a/contribs/gmf/src/datasource/OGC.js b/contribs/gmf/src/datasource/OGC.js index 08bdc88638f2..7d7e3640db06 100644 --- a/contribs/gmf/src/datasource/OGC.js +++ b/contribs/gmf/src/datasource/OGC.js @@ -27,8 +27,10 @@ import ngeoDatasourceOGC from 'ngeo/datasource/OGC.js'; * @property {boolean} [filtrable] Whether the data source is filtrable or not. * @property {string} [geometryName] The name of the geometry attribute. * @property {string} [ogcImageType] The type of images to fetch by queries by the (WMS) or (WMTS). - * @property {Array.} [ogcLayers] A list of layer definitions that - * are used by (WMS) and (WFS) queries. + * @property {Array} [wmsLayers] A list of layer definitions that are used by WMS queries. + * These are **not** used by the (WMTS) queries (the wmtsLayers is used by WMTS queries). + * @property {Array} [wfsLayers] A list of layer definitions that + * are used by WFS queries. * These are **not** used by the (WMTS) queries (the wmtsLayers is used by WMTS queries). * @property {string} [ogcServerType] The type of OGC server. * @property {string} [ogcType] The type data source. Can be: 'WMS' or 'WMTS'. diff --git a/contribs/gmf/src/datasource/WFSAliases.js b/contribs/gmf/src/datasource/WFSAliases.js index ccb053df260e..dc65dd304ab5 100644 --- a/contribs/gmf/src/datasource/WFSAliases.js +++ b/contribs/gmf/src/datasource/WFSAliases.js @@ -37,7 +37,7 @@ export class DatasourceWFSAlias { // Only QGIS Server supports WFS aliases if (dataSource.ogcServerType === ServerType.QGISSERVER && dataSource.wfsUrl_ && - dataSource.getOGCLayerNames().length == 1 && + dataSource.getWFSLayerNames().length == 1 && !dataSource.attributes) { // Trigger an additional WFS DescribeFeatureType request to get // datasource attributes, including aliases. diff --git a/contribs/gmf/src/filters/filterselectorComponent.js b/contribs/gmf/src/filters/filterselectorComponent.js index 8dd9287005d1..3d56af86ed51 100644 --- a/contribs/gmf/src/filters/filterselectorComponent.js +++ b/contribs/gmf/src/filters/filterselectorComponent.js @@ -475,7 +475,7 @@ class FilterSelectorController { * * 1) have its name in the list of filtrable layer node names * 2) support WFS - * 3) have only one ogcLayers defined + * 3) have only one wfsLayers defined * 4) the ogcLayer must be queryable * * If 1) is true but not any of the others, then the server has not been @@ -510,14 +510,14 @@ class FilterSelectorController { } // (3) The DS must have only one ogcLayer - if (!dataSource.ogcLayers || !dataSource.ogcLayers.length) { + if (!dataSource.wfsLayers || !dataSource.wfsLayers.length) { msgs.push(gettext.getString( - 'The data source must have only 1 ogcLayer defined.' + 'The data source must have only 1 wfsLayer defined.' )); - } else if (!dataSource.ogcLayers[0].queryable) { + } else if (!dataSource.wfsLayers[0].queryable) { // (4) The ogcLayer must be queryable msgs.push(gettext.getString( - 'The ogcLayer within the data source must be queryable.' + 'The wfsLayer within the data source must be queryable.' )); } diff --git a/contribs/gmf/src/permalink/Permalink.js b/contribs/gmf/src/permalink/Permalink.js index 357020b4d176..41e51f9ca026 100644 --- a/contribs/gmf/src/permalink/Permalink.js +++ b/contribs/gmf/src/permalink/Permalink.js @@ -1633,7 +1633,7 @@ PermalinkService.prototype.setExternalDataSourcesState_ = function() { // External WMS data sources always have only one OGC layer name, // as they are created using a single Capability Layer object that // has only 1 layer name - const layerName = wmsDataSource.getOGCLayerNames()[0]; + const layerName = wmsDataSource.getWFSLayerNames()[0]; wmsGroupLayerNames.push(layerName); } } diff --git a/examples/bboxquery.js b/examples/bboxquery.js index d7352a9d3c81..5ed9f559ac08 100644 --- a/examples/bboxquery.js +++ b/examples/bboxquery.js @@ -127,7 +127,11 @@ function MainController($scope, ngeoDataSources) { visible: true, wfsFeatureNS: MAPSERVER_WFS_FEATURE_NS, wfsUrl: MAPSERVER_PROXY, - ogcLayers: [{ + wmsLayers: [{ + name: 'bus_stop', + queryable: true + }], + wfsLayers: [{ name: 'bus_stop', queryable: true }] @@ -139,7 +143,11 @@ function MainController($scope, ngeoDataSources) { visible: true, wfsFeatureNS: MAPSERVER_WFS_FEATURE_NS, wfsUrl: MAPSERVER_PROXY, - ogcLayers: [{ + wmsLayers: [{ + name: 'information', + queryable: true + }], + wfsLayers: [{ name: 'information', queryable: true }] diff --git a/examples/mapquery.js b/examples/mapquery.js index 09a4378b4783..761c7ad86a56 100644 --- a/examples/mapquery.js +++ b/examples/mapquery.js @@ -138,7 +138,11 @@ function MainController($scope, ngeoDataSources, ngeoToolActivateMgr) { name: 'bus_stop', visible: true, wmsUrl: MAPSERVER_PROXY, - ogcLayers: [{ + wmsLayers: [{ + name: 'bus_stop', + queryable: true + }], + wfsLayers: [{ name: 'bus_stop', queryable: true }] @@ -149,7 +153,11 @@ function MainController($scope, ngeoDataSources, ngeoToolActivateMgr) { name: 'information', visible: true, wmsUrl: MAPSERVER_PROXY, - ogcLayers: [{ + wmsLayers: [{ + name: 'information', + queryable: true + }], + wfsLayers: [{ name: 'information', queryable: true }] diff --git a/src/datasource/Helper.js b/src/datasource/Helper.js index 65d754b6eea7..5b80ebbf33bf 100644 --- a/src/datasource/Helper.js +++ b/src/datasource/Helper.js @@ -97,7 +97,7 @@ export class DatasourceHelper { ).then((featureType) => { // We know, at this point, that there's only one definition that // was returned. Just to be sure, let's do a bunch of assertions. - const ogcLayerName = dataSource.getOGCLayerNames()[0]; + const ogcLayerName = dataSource.getWFSLayerNames()[0]; console.assert(typeof ogcLayerName == 'string', 'The data source should have only one ogcLayer.'); for (const element of featureType.element) { if (element.name === ogcLayerName) { diff --git a/src/datasource/OGC.js b/src/datasource/OGC.js index cba8047bd0c9..03ed467c6926 100644 --- a/src/datasource/OGC.js +++ b/src/datasource/OGC.js @@ -99,8 +99,9 @@ export const WMSInfoFormat = { * @property {boolean} [filtrable] Whether the data source is filtrable or not. * @property {string} [geometryName] The name of the geometry attribute. * @property {string} [ogcImageType] The type of images to fetch by queries by the (WMS) or (WMTS). - * @property {Array.} [ogcLayers] A list of layer definitions that are used by (WMS) and (WFS) - * queries. + * @property {Array} [wmsLayers] A list of layer definitions that are used by WMS queries. + * These are **not** used by the (WMTS) queries (the wmtsLayers is used by WMTS queries). + * @property {Array} [wfsLayers] A list of layer definitions that are used by WFS queries. * These are **not** used by the (WMTS) queries (the wmtsLayers is used by WMTS queries). * @property {string} [ogcServerType] The type of OGC server. * @property {string} [ogcType] The type data source. Can be: 'WMS' or 'WMTS'. @@ -142,7 +143,16 @@ export const WMSInfoFormat = { /** * The definition of a single layer (WMS) and/or featureType (WFS). * - * @typedef {Object} OGCLayer + * @typedef {Object} WMSLayer + * @property {string} name The layer name (WMS) and/or feature type name (WFS) + * @property {boolean} [queryable] Whether the the layer is queryable or not. Defaults to `false`. + */ + + +/** + * The definition of a single layer (WMS) and/or featureType (WFS). + * + * @typedef {Object} WFSLayer * @property {number} [maxResolution] The maximum resolution the layer should be rendered (when visible). * @property {number} [minResolution] The minimum resolution the layer should be rendered (when visible). * @property {string} name The layer name (WMS) and/or feature type name (WFS) @@ -280,13 +290,22 @@ class OGC extends ngeoDatasourceDataSource { this.ogcImageType_ = options.ogcImageType || 'image/png'; /** - * A list of layer definitions that are used by (WMS) and (WFS) queries. + * A list of layer definitions that are used by WMS queries. + * These are **not** used by the (WMTS) queries (the wmtsLayers is used + * by WMTS queries). + * @type {?Array} + * @private + */ + this.wmsLayers_ = options.wmsLayers || null; + + /** + * A list of layer definitions that are used by WFS queries. * These are **not** used by the (WMTS) queries (the wmtsLayers is used * by WMTS queries). - * @type {?Array.} + * @type {?Array} * @private */ - this.ogcLayers_ = options.ogcLayers || null; + this.wfsLayers_ = options.wfsLayers || null; /** * The type of OGC server making the requests. @@ -430,17 +449,30 @@ class OGC extends ngeoDatasourceDataSource { // === Calculated properties === // Get queryable ogc layer names - const layers = []; - if (this.queryable && this.ogcLayers) { - for (const ogcLayer of this.ogcLayers) { - if (ogcLayer.queryable) { - layers.push(ogcLayer.name); + const wfsLayers = []; + if (this.queryable && this.wfsLayers) { + for (const wfsLayer of this.wfsLayers) { + if (wfsLayer.queryable) { + wfsLayers.push(wfsLayer.name); + } + } + } + const wmsLayers = []; + if (this.queryable) { + for (const wmsLayer of (this.wmsLayers || [])) { + if (wmsLayer.queryable) { + wmsLayers.push(wmsLayer.name); + } + } + for (const wfsLayer of this.wfsLayers || []) { + if (wfsLayer.queryable) { + wmsLayers.push(wfsLayer.name); } } } let wfsFormat = null; - if (this.supportsWFS && layers.length) { + if (this.supportsWFS && wfsLayers.length) { let format = undefined; if (this.wfsOutputFormat_ === WFSOutputFormat.GML3) { format = new olFormatGML3(); @@ -450,7 +482,7 @@ class OGC extends ngeoDatasourceDataSource { console.assert(format); wfsFormat = new olFormatWFS({ featureNS: this.wfsFeatureNS, - featureType: layers, + featureType: wfsLayers, gmlFormat: format }); } @@ -462,10 +494,10 @@ class OGC extends ngeoDatasourceDataSource { this.wfsFormat_ = wfsFormat; let wmsFormat = null; - if (this.supportsWMS && layers.length) { + if (this.supportsWMS && wmsLayers.length) { if (this.wmsInfoFormat === WMSInfoFormat.GML) { wmsFormat = new olFormatWMSGetFeatureInfo({ - layers + layers: wmsLayers }); } // Todo, support more formats for WMS @@ -572,10 +604,17 @@ class OGC extends ngeoDatasourceDataSource { } /** - * @return {?Array.} OGC layers + * @return {?Array} WMS layers */ - get ogcLayers() { - return this.ogcLayers_; + get wmsLayers() { + return this.wmsLayers_; + } + + /** + * @return {?Array} TFS layers + */ + get wfsLayers() { + return this.wfsLayers_; } /** @@ -762,15 +801,17 @@ class OGC extends ngeoDatasourceDataSource { */ get queryable() { let queryable = false; - const supportsOGCQueries = this.supportsWMS || this.supportsWFS; - if (supportsOGCQueries && this.ogcLayers) { - for (const ogcLayer of this.ogcLayers) { - if (ogcLayer.queryable === true) { + if (this.supportsWFS && this.wfsLayers) { + for (const wfsLayer of this.wfsLayers) { + if (wfsLayer.queryable === true) { queryable = true; break; } } } + if (this.supportsWMS && this.wmsLayers && this.wmsLayers.length > 0) { + queryable = true; + } return queryable; } @@ -797,9 +838,9 @@ class OGC extends ngeoDatasourceDataSource { get supportsAttributes() { return this.attributes !== null || ( this.supportsWFS && - this.ogcLayers !== null && - this.ogcLayers.length === 1 && - this.ogcLayers[0].queryable === true + this.wfsLayers !== null && + this.wfsLayers.length === 1 && + this.wfsLayers[0].queryable === true ); } @@ -874,31 +915,52 @@ class OGC extends ngeoDatasourceDataSource { * @return {boolean} At least one OGC layer is in range. */ isAnyOGCLayerInRange(res, queryableOnly = false) { - return !!(this.getInRangeOGCLayerNames(res, queryableOnly).length); + return !!(this.getInRangeWFSLayerNames(res, queryableOnly).length); + } + + /** + * Returns the list of WMS layer names. + * @param {boolean} queryableOnly Whether to additionally check if the + * WMS layer is queryable as well or not. Defaults to `false`. + * @return {Array} The WMS layer names. + */ + getWMSLayerNames(queryableOnly = false) { + + const layerNames = []; + + if (this.wmsLayers) { + for (const wmsLayer of this.wmsLayers) { + if (!queryableOnly || wmsLayer.queryable) { + layerNames.push(wmsLayer.name); + } + } + } + + return layerNames; } /** - * Returns a list of OGC layer names that are in range of a given resolution. - * If there's no OGC layers defined, an empty array is returned. + * Returns a list of WFS layer names that are in range of a given resolution. + * If there's no WFS layers defined, an empty array is returned. * @param {number} res Resolution. * @param {boolean} queryableOnly Whether to additionally check if the - * OGC layer is queryable as well or not. Defaults to `false`. - * @return {Array.} The OGC layer names that are in range. + * WFS layer is queryable as well or not. Defaults to `false`. + * @return {Array} The WFS layer names that are in range. */ - getInRangeOGCLayerNames(res, queryableOnly = false) { + getInRangeWFSLayerNames(res, queryableOnly = false) { const layerNames = []; - if (this.ogcLayers) { - for (const ogcLayer of this.ogcLayers) { - const maxRes = ogcLayer.maxResolution; - const minRes = ogcLayer.minResolution; + if (this.wfsLayers) { + for (const wfsLayer of this.wfsLayers) { + const maxRes = wfsLayer.maxResolution; + const minRes = wfsLayer.minResolution; const inMinRange = minRes === undefined || res >= minRes; const inMaxRange = maxRes === undefined || res <= maxRes; const inRange = inMinRange && inMaxRange; - if (inRange && (!queryableOnly || ogcLayer.queryable)) { - layerNames.push(ogcLayer.name); + if (inRange && (!queryableOnly || wfsLayer.queryable)) { + layerNames.push(wfsLayer.name); } } } @@ -907,19 +969,19 @@ class OGC extends ngeoDatasourceDataSource { } /** - * Returns the list of OGC layer names. + * Returns the list of WFS layer names. * @param {boolean} queryableOnly Whether to additionally check if the - * OGC layer is queryable as well or not. Defaults to `false`. - * @return {Array.} The OGC layer names. + * WFS layer is queryable as well or not. Defaults to `false`. + * @return {Array} The WFS layer names. */ - getOGCLayerNames(queryableOnly = false) { + getWFSLayerNames(queryableOnly = false) { const layerNames = []; - if (this.ogcLayers) { - for (const ogcLayer of this.ogcLayers) { - if (!queryableOnly || ogcLayer.queryable) { - layerNames.push(ogcLayer.name); + if (this.wfsLayers) { + for (const wfsLayer of this.wfsLayers) { + if (!queryableOnly || wfsLayer.queryable) { + layerNames.push(wfsLayer.name); } } } @@ -928,13 +990,13 @@ class OGC extends ngeoDatasourceDataSource { } /** - * Returns the filtrable OGC layer name. This methods asserts that + * Returns the filtrable WFS layer name. This methods asserts that * the name exists and is filtrable. - * @return {string} OGC layer name. + * @return {string} WFS layer name. */ - getFiltrableOGCLayerName() { + getFiltrableWFSLayerName() { console.assert(this.filtrable); - const layerNames = this.getOGCLayerNames(); + const layerNames = this.getWFSLayerNames(); console.assert(layerNames.length === 1); return layerNames[0]; } diff --git a/src/datasource/WMSGroup.js b/src/datasource/WMSGroup.js index e4d6a61bbc58..8b881a1a88cf 100644 --- a/src/datasource/WMSGroup.js +++ b/src/datasource/WMSGroup.js @@ -166,7 +166,7 @@ export default class extends ngeoDatasourceOGCGroup { // (1) Collect layer names from data sources in the group for (const dataSource of this.dataSources) { if (dataSource instanceof ngeoDatasourceOGC && dataSource.visible) { - layerNames = layerNames.concat(dataSource.getOGCLayerNames()); + layerNames = layerNames.concat(dataSource.getWFSLayerNames()); } } diff --git a/src/map/LayerHelper.js b/src/map/LayerHelper.js index b696b6193474..afa458b76f1b 100644 --- a/src/map/LayerHelper.js +++ b/src/map/LayerHelper.js @@ -124,7 +124,7 @@ LayerHelper.prototype.createBasicWMSLayerFromDataSource = function( const url = dataSource.wmsUrl; console.assert(url); - const layerNames = dataSource.getOGCLayerNames().join(','); + const layerNames = dataSource.getWFSLayerNames().join(','); const serverType = dataSource.ogcServerType; const imageType = dataSource.ogcImageType; diff --git a/src/query/Querent.js b/src/query/Querent.js index ec82a81bcc86..3027791b4b5e 100644 --- a/src/query/Querent.js +++ b/src/query/Querent.js @@ -257,13 +257,13 @@ export class Querent { is queryable in order to issue WFS DescribeFeatureType requests` ); - const ogcLayerNames = dataSource.getOGCLayerNames(); + const wfsLayerNames = dataSource.getWFSLayerNames(); const url = olUriAppendParams(dataSource.wfsUrl, { 'REQUEST': 'DescribeFeatureType', 'SERVICE': 'WFS', 'VERSION': '2.0.0', - 'TYPENAME': ogcLayerNames + 'TYPENAME': wfsLayerNames }); return this.http_.get(url).then((response) => { @@ -464,7 +464,7 @@ export class Querent { * The type will be stocked in the properties of the features as * "ngeo_feature_type_". * @param {ngeoDatasourceOGC} dataSource used to read the features. - * @param {Document | Node | Object | string} data the response data. + * @param {string} data the response data. * @param {boolean} wfs Whether the query was WFS or WMS. * @return {Array.} returned features with a type in each features. * @private @@ -604,8 +604,7 @@ export class Querent { } // (b) Add queryable layer names in featureTypes array - featureTypes = featureTypes.concat( - dataSource.getInRangeOGCLayerNames(resolution, true)); + featureTypes = featureTypes.concat(dataSource.getInRangeWFSLayerNames(resolution, true)); // (c) Add filter, if any. If the case, then only one data source // is expected to be used for this request. @@ -792,8 +791,7 @@ export class Querent { } // (b) Add queryable layer names in featureTypes array - LAYERS = LAYERS.concat( - dataSource.getInRangeOGCLayerNames(resolution, true)); + LAYERS = LAYERS.concat(dataSource.getWMSLayerNames(true)); // (c) Manage active dimensions, which are added directly to the // query parameters. Note that this occurs only ONCE, i.e. @@ -810,7 +808,7 @@ export class Querent { // data source only. if (dataSource.filterRules && dataSource.filterRules.length) { console.assert(dataSources.length === 1); - filtrableLayerName = dataSource.getFiltrableOGCLayerName(); + filtrableLayerName = dataSource.getFiltrableWFSLayerName(); filterString = this.ngeoRuleHelper_.createFilterString({ dataSource: dataSource, srsName: projCode