コード例 #1
0
ファイル: qgstransaction.cpp プロジェクト: spono/QGIS
bool QgsTransaction::addLayer( QgsVectorLayer* layer )
{
  if ( !layer )
    return false;

  if ( layer->isEditable() )
    return false;

  //test if provider supports transactions
  if ( !layer->dataProvider() || ( layer->dataProvider()->capabilities() & QgsVectorDataProvider::TransactionSupport ) == 0 )
    return false;

  if ( layer->dataProvider()->transaction() )
    return false;

  //connection string not compatible
  if ( QgsDataSourceUri( layer->source() ).connectionInfo( false ) != mConnString )
  {
    QgsDebugMsg( QString( "Couldn't start transaction because connection string for layer %1 : '%2' does not match '%3'" ).arg(
                   layer->id(), QgsDataSourceUri( layer->source() ).connectionInfo( false ), mConnString ) );
    return false;
  }

  connect( this, &QgsTransaction::afterRollback, layer->dataProvider(), &QgsVectorDataProvider::dataChanged );
  connect( QgsProject::instance(), SIGNAL( layersWillBeRemoved( QStringList ) ), this, SLOT( onLayersDeleted( QStringList ) ) );
  mLayers.insert( layer );

  if ( mTransactionActive )
    layer->dataProvider()->setTransaction( this );

  return true;
}
コード例 #2
0
ファイル: qgstransaction.cpp プロジェクト: spono/QGIS
QgsTransaction* QgsTransaction::create( const QStringList& layerIds )
{
  if ( layerIds.isEmpty() )
    return nullptr;

  QgsVectorLayer* layer = qobject_cast<QgsVectorLayer*>( QgsProject::instance()->mapLayer( layerIds.first() ) );
  if ( !layer )
    return nullptr;

  QString connStr = QgsDataSourceUri( layer->source() ).connectionInfo( false );
  QString providerKey = layer->dataProvider()->name();
  QgsTransaction* ts = QgsTransaction::create( connStr, providerKey );
  if ( !ts )
    return nullptr;

  Q_FOREACH ( const QString& layerId, layerIds )
  {
    if ( !ts->addLayer( layerId ) )
    {
      delete ts;
      return nullptr;
    }
  }
  return ts;
}
コード例 #3
0
ファイル: qgsdb2provider.cpp プロジェクト: mterente/QGIS
bool QgsDb2Provider::setSubsetString( const QString& theSQL, bool )
{
  QString prevWhere = mSqlWhereClause;
  QgsDebugMsg( theSQL );
  mSqlWhereClause = theSQL.trimmed();

  QString sql = QString( "SELECT COUNT(*) FROM " );

  sql += QString( "%1.%2" ).arg( mSchemaName, mTableName );

  if ( !mSqlWhereClause.isEmpty() )
  {
    sql += QString( " WHERE %1" ).arg( mSqlWhereClause );
  }

  if ( !openDatabase( mDatabase ) )
  {
    return false;
  }

  QSqlQuery query = QSqlQuery( mDatabase );
  query.setForwardOnly( true );
  QgsDebugMsg( sql );
  if ( !query.exec( sql ) )
  {
    pushError( query.lastError().text() );
    mSqlWhereClause = prevWhere;
    QgsDebugMsg( query.lastError().text() );
    return false;
  }

  if ( query.isActive() && query.next() )
  {
    mNumberFeatures = query.value( 0 ).toInt();
    QgsDebugMsg( QString( "count: %1" ).arg( mNumberFeatures ) );
  }
  else
  {
    pushError( query.lastError().text() );
    mSqlWhereClause = prevWhere;
    QgsDebugMsg( query.lastError().text() );
    return false;
  }

  QgsDataSourceUri anUri = QgsDataSourceUri( dataSourceUri() );
  anUri.setSql( mSqlWhereClause );

  setDataSourceUri( anUri.uri() );

  mExtent.setMinimal();

  emit dataChanged();

  return true;
}
コード例 #4
0
QgsWFSDataSourceURI::QgsWFSDataSourceURI( const QString& uri )
    : mURI( uri )
{
  // Compatiblity with QGIS < 2.16 layer URI of the format
  // http://example.com/?SERVICE=WFS&VERSION=1.0.0&REQUEST=GetFeature&TYPENAME=x&SRSNAME=y&username=foo&password=
  if ( !mURI.hasParam( QgsWFSConstants::URI_PARAM_URL ) )
  {
    QUrl url( uri );
    QString srsname = url.queryItemValue( "SRSNAME" );
    QString bbox = url.queryItemValue( "BBOX" );
    QString typeName = url.queryItemValue( "TYPENAME" );
    QString filter = url.queryItemValue( "FILTER" );
    mAuth.mUserName = url.queryItemValue( QgsWFSConstants::URI_PARAM_USERNAME );
    mAuth.mPassword = url.queryItemValue( QgsWFSConstants::URI_PARAM_PASSWORD );
    mAuth.mAuthCfg = url.queryItemValue( QgsWFSConstants::URI_PARAM_AUTHCFG );

    // Now remove all stuff that is not the core URL
    url.removeQueryItem( "SERVICE" );
    url.removeQueryItem( "VERSION" );
    url.removeQueryItem( "TYPENAME" );
    url.removeQueryItem( "REQUEST" );
    url.removeQueryItem( "BBOX" );
    url.removeQueryItem( "SRSNAME" );
    url.removeQueryItem( "FILTER" );
    url.removeQueryItem( QgsWFSConstants::URI_PARAM_USERNAME );
    url.removeQueryItem( QgsWFSConstants::URI_PARAM_PASSWORD );
    url.removeQueryItem( QgsWFSConstants::URI_PARAM_AUTHCFG );

    mURI = QgsDataSourceUri();
    mURI.setParam( QgsWFSConstants::URI_PARAM_URL, url.toEncoded() );
    setTypeName( typeName );
    setSRSName( srsname );

    //if the xml comes from the dialog, it needs to be a string to pass the validity test
    if ( filter.startsWith( '\'' ) && filter.endsWith( '\'' ) && filter.size() > 1 )
    {
      filter.chop( 1 );
      filter.remove( 0, 1 );
    }

    setFilter( filter );
    if ( !bbox.isEmpty() )
      mURI.setParam( QgsWFSConstants::URI_PARAM_RESTRICT_TO_REQUEST_BBOX, "1" );
  }
  else
  {
    mAuth.mUserName = mURI.param( QgsWFSConstants::URI_PARAM_USERNAME );
    mAuth.mPassword = mURI.param( QgsWFSConstants::URI_PARAM_PASSWORD );
    mAuth.mAuthCfg = mURI.param( QgsWFSConstants::URI_PARAM_AUTHCFG );
  }
}
コード例 #5
0
ファイル: qgsafsprovider.cpp プロジェクト: CS-SI/QGIS
QgsAfsProvider::QgsAfsProvider( const QString &uri )
  : QgsVectorDataProvider( uri )
  , mValid( false )
  , mObjectIdFieldIdx( -1 )
{
  mSharedData.reset( new QgsAfsSharedData() );
  mSharedData->mGeometryType = QgsWkbTypes::Unknown;
  mSharedData->mDataSource = QgsDataSourceUri( uri );

  // Set CRS
  mSharedData->mSourceCRS = QgsCoordinateReferenceSystem::fromOgcWmsCrs( mSharedData->mDataSource.param( QStringLiteral( "crs" ) ) );

  // Get layer info
  QString errorTitle, errorMessage;
  const QVariantMap layerData = QgsArcGisRestUtils::getLayerInfo( mSharedData->mDataSource.param( QStringLiteral( "url" ) ), errorTitle, errorMessage );
  if ( layerData.isEmpty() )
  {
    pushError( errorTitle + ": " + errorMessage );
    appendError( QgsErrorMessage( tr( "getLayerInfo failed" ), QStringLiteral( "AFSProvider" ) ) );
    return;
  }
  mLayerName = layerData[QStringLiteral( "name" )].toString();
  mLayerDescription = layerData[QStringLiteral( "description" )].toString();

  // Set extent
  QStringList coords = mSharedData->mDataSource.param( QStringLiteral( "bbox" ) ).split( ',' );
  if ( coords.size() == 4 )
  {
    bool xminOk = false, yminOk = false, xmaxOk = false, ymaxOk = false;
    mSharedData->mExtent.setXMinimum( coords[0].toDouble( &xminOk ) );
    mSharedData->mExtent.setYMinimum( coords[1].toDouble( &yminOk ) );
    mSharedData->mExtent.setXMaximum( coords[2].toDouble( &xmaxOk ) );
    mSharedData->mExtent.setYMaximum( coords[3].toDouble( &ymaxOk ) );
    if ( !xminOk || !yminOk || !xmaxOk || !ymaxOk )
      mSharedData->mExtent = QgsRectangle();
  }

  const QVariantMap layerExtentMap = layerData[QStringLiteral( "extent" )].toMap();
  bool xminOk = false, yminOk = false, xmaxOk = false, ymaxOk = false;
  QgsRectangle originalExtent;
  originalExtent.setXMinimum( layerExtentMap[QStringLiteral( "xmin" )].toDouble( &xminOk ) );
  originalExtent.setYMinimum( layerExtentMap[QStringLiteral( "ymin" )].toDouble( &yminOk ) );
  originalExtent.setXMaximum( layerExtentMap[QStringLiteral( "xmax" )].toDouble( &xmaxOk ) );
  originalExtent.setYMaximum( layerExtentMap[QStringLiteral( "ymax" )].toDouble( &ymaxOk ) );
  if ( mSharedData->mExtent.isEmpty() && ( !xminOk || !yminOk || !xmaxOk || !ymaxOk ) )
  {
    appendError( QgsErrorMessage( tr( "Could not retrieve layer extent" ), QStringLiteral( "AFSProvider" ) ) );
    return;
  }
  QgsCoordinateReferenceSystem extentCrs = QgsArcGisRestUtils::parseSpatialReference( layerExtentMap[QStringLiteral( "spatialReference" )].toMap() );
  if ( mSharedData->mExtent.isEmpty() && !extentCrs.isValid() )
  {
    appendError( QgsErrorMessage( tr( "Could not parse spatial reference" ), QStringLiteral( "AFSProvider" ) ) );
    return;
  }

  if ( xminOk && yminOk && xmaxOk && ymaxOk )
  {
    QgsLayerMetadata::SpatialExtent spatialExtent;
    spatialExtent.bounds = QgsBox3d( originalExtent );
    spatialExtent.extentCrs = extentCrs;
    QgsLayerMetadata::Extent metadataExtent;
    metadataExtent.setSpatialExtents( QList<  QgsLayerMetadata::SpatialExtent >() << spatialExtent );
    mLayerMetadata.setExtent( metadataExtent );
  }
  if ( extentCrs.isValid() )
  {
    mLayerMetadata.setCrs( extentCrs );
  }

  if ( mSharedData->mExtent.isEmpty() )
  {
    mSharedData->mExtent = originalExtent;
    Q_NOWARN_DEPRECATED_PUSH
    mSharedData->mExtent = QgsCoordinateTransform( extentCrs, mSharedData->mSourceCRS ).transformBoundingBox( mSharedData->mExtent );
    Q_NOWARN_DEPRECATED_POP
  }
コード例 #6
0
ファイル: qgsafsprovider.cpp プロジェクト: V17nika/QGIS
QgsAfsProvider::QgsAfsProvider( const QString& uri )
    : QgsVectorDataProvider( uri )
    , mValid( false )
    , mGeometryType( QgsWkbTypes::Unknown )
    , mObjectIdFieldIdx( -1 )
{
  mDataSource = QgsDataSourceUri( uri );

  // Set CRS
  mSourceCRS = QgsCoordinateReferenceSystem::fromOgcWmsCrs( mDataSource.param( "crs" ) );

  // Get layer info
  QString errorTitle, errorMessage;
  QVariantMap layerData = QgsArcGisRestUtils::getLayerInfo( mDataSource.param( "url" ), errorTitle, errorMessage );
  if ( layerData.isEmpty() )
  {
    pushError( errorTitle + ": " + errorMessage );
    appendError( QgsErrorMessage( tr( "getLayerInfo failed" ), "AFSProvider" ) );
    return;
  }
  mLayerName = layerData["name"].toString();
  mLayerDescription = layerData["description"].toString();

  // Set extent
  QStringList coords = mDataSource.param( "bbox" ).split( "," );
  if ( coords.size() == 4 )
  {
    bool xminOk = false, yminOk = false, xmaxOk = false, ymaxOk = false;
    mExtent.setXMinimum( coords[0].toDouble( &xminOk ) );
    mExtent.setYMinimum( coords[1].toDouble( &yminOk ) );
    mExtent.setXMaximum( coords[2].toDouble( &xmaxOk ) );
    mExtent.setYMaximum( coords[3].toDouble( &ymaxOk ) );
    if ( !xminOk || !yminOk || !xmaxOk || !ymaxOk )
      mExtent = QgsRectangle();
  }
  if ( mExtent.isEmpty() )
  {
    QVariantMap layerExtentMap = layerData["extent"].toMap();
    bool xminOk = false, yminOk = false, xmaxOk = false, ymaxOk = false;
    mExtent.setXMinimum( layerExtentMap["xmin"].toDouble( &xminOk ) );
    mExtent.setYMinimum( layerExtentMap["ymin"].toDouble( &yminOk ) );
    mExtent.setXMaximum( layerExtentMap["xmax"].toDouble( &xmaxOk ) );
    mExtent.setYMaximum( layerExtentMap["ymax"].toDouble( &ymaxOk ) );
    if ( !xminOk || !yminOk || !xmaxOk || !ymaxOk )
    {
      appendError( QgsErrorMessage( tr( "Could not retrieve layer extent" ), "AFSProvider" ) );
      return;
    }
    QgsCoordinateReferenceSystem extentCrs = QgsArcGisRestUtils::parseSpatialReference( layerExtentMap["spatialReference"].toMap() );
    if ( !extentCrs.isValid() )
    {
      appendError( QgsErrorMessage( tr( "Could not parse spatial reference" ), "AFSProvider" ) );
      return;
    }
    mExtent = QgsCoordinateTransform( extentCrs, mSourceCRS ).transformBoundingBox( mExtent );
  }

  // Read fields
  foreach ( const QVariant& fieldData, layerData["fields"].toList() )
  {
    QVariantMap fieldDataMap = fieldData.toMap();
    QString fieldName = fieldDataMap["name"].toString();
    QVariant::Type type = QgsArcGisRestUtils::mapEsriFieldType( fieldDataMap["type"].toString() );
    if ( fieldName == "geometry" || type == QVariant::Invalid )
    {
      QgsDebugMsg( QString( "Skipping unsupported (or possibly geometry) field" ).arg( fieldName ) );
      continue;
    }
    QgsField field( fieldName, type, fieldDataMap["type"].toString(), fieldDataMap["length"].toInt() );
    mFields.append( field );
  }

  // Determine geometry type
  bool hasM = layerData["hasM"].toBool();
  bool hasZ = layerData["hasZ"].toBool();
  mGeometryType = QgsArcGisRestUtils::mapEsriGeometryType( layerData["geometryType"].toString() );
  if ( mGeometryType == QgsWkbTypes::Unknown )
  {
    appendError( QgsErrorMessage( tr( "Failed to determine geometry type" ), "AFSProvider" ) );
    return;
  }
  mGeometryType = QgsWkbTypes::zmType( mGeometryType, hasZ, hasM );

  // Read OBJECTIDs of all features: these may not be a continuous sequence,
  // and we need to store these to iterate through the features. This query
  // also returns the name of the ObjectID field.
  QVariantMap objectIdData = QgsArcGisRestUtils::getObjectIds( mDataSource.param( "url" ), errorTitle, errorMessage );
  if ( objectIdData.isEmpty() )
  {
    appendError( QgsErrorMessage( tr( "getObjectIds failed: %1 - %2" ).arg( errorTitle ).arg( errorMessage ), "AFSProvider" ) );
    return;
  }
  if ( !objectIdData["objectIdFieldName"].isValid() || !objectIdData["objectIds"].isValid() )
  {
    appendError( QgsErrorMessage( tr( "Failed to determine objectIdFieldName and/or objectIds" ), "AFSProvider" ) );
    return;
  }
  mObjectIdFieldName = objectIdData["objectIdFieldName"].toString();
  for ( int idx = 0, nIdx = mFields.count(); idx < nIdx; ++idx )
  {
    if ( mFields.at( idx ).name() == mObjectIdFieldName )
    {
      mObjectIdFieldIdx = idx;
      break;
    }
  }
  foreach ( const QVariant& objectId, objectIdData["objectIds"].toList() )
  {
    mObjectIds.append( objectId.toInt() );
  }

  mValid = true;
}
コード例 #7
0
ファイル: qgsdb2provider.cpp プロジェクト: mterente/QGIS
QgsDb2Provider::QgsDb2Provider( QString uri )
    : QgsVectorDataProvider( uri )
    , mNumberFeatures( 0 )
    , mEnvironment( ENV_LUW )
    , mWkbType( QgsWkbTypes::Unknown )
{
  QgsDebugMsg( "uri: " + uri );
  QgsDataSourceUri anUri = QgsDataSourceUri( uri );
  if ( !anUri.srid().isEmpty() )
    mSRId = anUri.srid().toInt();
  else
    mSRId = -1;

  if ( 0 != anUri.wkbType() )
  {
    mWkbType = anUri.wkbType();
  }
  QgsDebugMsg( QString( "mWkbType: %1" ).arg( mWkbType ) );
  QgsDebugMsg( QString( "new mWkbType: %1" ).arg( anUri.wkbType() ) );

  mValid = true;
  mSkipFailures = false;
  int dim; // Not used
  db2WkbTypeAndDimension( mWkbType, mGeometryColType, dim ); // Get DB2 geometry type name

  mFidColName = anUri.keyColumn().toUpper();
  QgsDebugMsg( "mFidColName " + mFidColName );
  mExtents = anUri.param( "extents" );
  QgsDebugMsg( "mExtents " + mExtents );

  mUseEstimatedMetadata = anUri.useEstimatedMetadata();
  QgsDebugMsg( QString( "mUseEstimatedMetadata: '%1'" ).arg( mUseEstimatedMetadata ) );
  mSqlWhereClause = anUri.sql();
  QString errMsg;
  mDatabase = getDatabase( uri, errMsg );
  mConnInfo = anUri.connectionInfo();
  QgsCoordinateReferenceSystem layerCrs = crs();
  QgsDebugMsg( "CRS: " + layerCrs.toWkt() );

  if ( !errMsg.isEmpty() )
  {
    setLastError( errMsg );
    QgsDebugMsg( mLastError );
    mValid = false;
    return;
  }

  // Create a query for default connection
  mQuery = QSqlQuery( mDatabase );

  mSchemaName = anUri.schema();

  mTableName = anUri.table().toUpper();
  QStringList sl = mTableName.split( '.' );
  if ( sl.length() == 2 )  // Never seems to be the case
  {
    mSchemaName = sl[0];
    mTableName = sl[1];
  }
  if ( mSchemaName.isEmpty() )
  {
    mSchemaName = anUri.username().toUpper();
  }

  QgsDebugMsg( "mSchemaName: '" + mSchemaName + "; mTableName: '" + mTableName );

  if ( !anUri.geometryColumn().isEmpty() )
    mGeometryColName = anUri.geometryColumn().toUpper();

  loadFields();
  updateStatistics();

  if ( mGeometryColName.isEmpty() )
  {
    // table contains no geometries
    mWkbType = QgsWkbTypes::NoGeometry;
    mSRId = 0;
  }

  //fill type names into sets
  mNativeTypes
  // integer types
  << QgsVectorDataProvider::NativeType( tr( "8 Bytes integer" ), "bigint", QVariant::Int )
  << QgsVectorDataProvider::NativeType( tr( "4 Bytes integer" ), "integer", QVariant::Int )
  << QgsVectorDataProvider::NativeType( tr( "2 Bytes integer" ), "smallint", QVariant::Int )
  << QgsVectorDataProvider::NativeType( tr( "Decimal number (numeric)" ), "numeric", QVariant::Double, 1, 31, 0, 31 )
  << QgsVectorDataProvider::NativeType( tr( "Decimal number (decimal)" ), "decimal", QVariant::Double, 1, 31, 0, 31 )

  // floating point
  << QgsVectorDataProvider::NativeType( tr( "Decimal number (real)" ), "real", QVariant::Double )
  << QgsVectorDataProvider::NativeType( tr( "Decimal number (double)" ), "double", QVariant::Double )

  // date/time types
  << QgsVectorDataProvider::NativeType( tr( "Date" ), "date", QVariant::Date, -1, -1, -1, -1 )
  << QgsVectorDataProvider::NativeType( tr( "Time" ), "time", QVariant::Time, -1, -1, -1, -1 )
  << QgsVectorDataProvider::NativeType( tr( "Date & Time" ), "datetime", QVariant::DateTime, -1, -1, -1, -1 )

  // string types
  << QgsVectorDataProvider::NativeType( tr( "Text, fixed length (char)" ), "char", QVariant::String, 1, 254 )
  << QgsVectorDataProvider::NativeType( tr( "Text, variable length (varchar)" ), "varchar", QVariant::String, 1, 32704 )
  << QgsVectorDataProvider::NativeType( tr( "Text, variable length large object (clob)" ), "clob", QVariant::String, 1, 2147483647 )
  //DBCLOB is for 1073741824 double-byte characters, data length should be the same as CLOB (2147483647)?
  << QgsVectorDataProvider::NativeType( tr( "Text, variable length large object (dbclob)" ), "dbclob", QVariant::String, 1, 1073741824 )
  ;
}
コード例 #8
0
ファイル: qgsafsprovider.cpp プロジェクト: mbernasocchi/QGIS
QgsAfsProvider::QgsAfsProvider( const QString &uri, const ProviderOptions &options )
  : QgsVectorDataProvider( uri, options )
{
  mSharedData.reset( new QgsAfsSharedData() );
  mSharedData->mGeometryType = QgsWkbTypes::Unknown;
  mSharedData->mDataSource = QgsDataSourceUri( uri );

  const QString authcfg = mSharedData->mDataSource.authConfigId();

  // Set CRS
  mSharedData->mSourceCRS.createFromString( mSharedData->mDataSource.param( QStringLiteral( "crs" ) ) );

  // Get layer info
  QString errorTitle, errorMessage;

  const QString referer = mSharedData->mDataSource.param( QStringLiteral( "referer" ) );
  if ( !referer.isEmpty() )
    mRequestHeaders[ QStringLiteral( "Referer" )] = referer;

  const QVariantMap layerData = QgsArcGisRestUtils::getLayerInfo( mSharedData->mDataSource.param( QStringLiteral( "url" ) ),
                                authcfg, errorTitle, errorMessage, mRequestHeaders );
  if ( layerData.isEmpty() )
  {
    pushError( errorTitle + ": " + errorMessage );
    appendError( QgsErrorMessage( tr( "getLayerInfo failed" ), QStringLiteral( "AFSProvider" ) ) );
    return;
  }
  mLayerName = layerData[QStringLiteral( "name" )].toString();
  mLayerDescription = layerData[QStringLiteral( "description" )].toString();

  // Set extent
  QStringList coords = mSharedData->mDataSource.param( QStringLiteral( "bbox" ) ).split( ',' );
  bool limitBbox = false;
  if ( coords.size() == 4 )
  {
    bool xminOk = false, yminOk = false, xmaxOk = false, ymaxOk = false;
    mSharedData->mExtent.setXMinimum( coords[0].toDouble( &xminOk ) );
    mSharedData->mExtent.setYMinimum( coords[1].toDouble( &yminOk ) );
    mSharedData->mExtent.setXMaximum( coords[2].toDouble( &xmaxOk ) );
    mSharedData->mExtent.setYMaximum( coords[3].toDouble( &ymaxOk ) );
    if ( !xminOk || !yminOk || !xmaxOk || !ymaxOk )
      mSharedData->mExtent = QgsRectangle();
    else
    {
      // user has set a bounding box limit on the layer - so we only EVER fetch features from this extent
      limitBbox = true;
    }
  }

  const QVariantMap layerExtentMap = layerData[QStringLiteral( "extent" )].toMap();
  bool xminOk = false, yminOk = false, xmaxOk = false, ymaxOk = false;
  QgsRectangle originalExtent;
  originalExtent.setXMinimum( layerExtentMap[QStringLiteral( "xmin" )].toDouble( &xminOk ) );
  originalExtent.setYMinimum( layerExtentMap[QStringLiteral( "ymin" )].toDouble( &yminOk ) );
  originalExtent.setXMaximum( layerExtentMap[QStringLiteral( "xmax" )].toDouble( &xmaxOk ) );
  originalExtent.setYMaximum( layerExtentMap[QStringLiteral( "ymax" )].toDouble( &ymaxOk ) );
  if ( mSharedData->mExtent.isEmpty() && ( !xminOk || !yminOk || !xmaxOk || !ymaxOk ) )
  {
    appendError( QgsErrorMessage( tr( "Could not retrieve layer extent" ), QStringLiteral( "AFSProvider" ) ) );
    return;
  }
  QgsCoordinateReferenceSystem extentCrs = QgsArcGisRestUtils::parseSpatialReference( layerExtentMap[QStringLiteral( "spatialReference" )].toMap() );
  if ( mSharedData->mExtent.isEmpty() && !extentCrs.isValid() )
  {
    appendError( QgsErrorMessage( tr( "Could not parse spatial reference" ), QStringLiteral( "AFSProvider" ) ) );
    return;
  }

  if ( xminOk && yminOk && xmaxOk && ymaxOk )
  {
    QgsLayerMetadata::SpatialExtent spatialExtent;
    spatialExtent.bounds = QgsBox3d( originalExtent );
    spatialExtent.extentCrs = extentCrs;
    QgsLayerMetadata::Extent metadataExtent;
    metadataExtent.setSpatialExtents( QList<  QgsLayerMetadata::SpatialExtent >() << spatialExtent );
    mLayerMetadata.setExtent( metadataExtent );
  }
  if ( extentCrs.isValid() )
  {
    mLayerMetadata.setCrs( extentCrs );
  }

  if ( mSharedData->mExtent.isEmpty() )
  {
    mSharedData->mExtent = originalExtent;
    Q_NOWARN_DEPRECATED_PUSH
    mSharedData->mExtent = QgsCoordinateTransform( extentCrs, mSharedData->mSourceCRS ).transformBoundingBox( mSharedData->mExtent );
    Q_NOWARN_DEPRECATED_POP
  }