func reviewController()

in firestore/FirestoreExample/RestaurantDetailViewController.swift [126:193]


  func reviewController(_ controller: NewReviewViewController,
                        didSubmitFormWithReview review: Review) {
    guard let reference = restaurantReference else { return }
    let reviewsCollection = reference.collection("ratings")
    let newReviewReference = reviewsCollection.document()

    // Writing data in a transaction

    let firestore = Firestore.firestore()
    firestore.runTransaction({ (transaction, errorPointer) -> Any? in

      // Read data from Firestore inside the transaction, so we don't accidentally
      // update using stale client data. Error if we're unable to read here.
      let restaurantSnapshot: DocumentSnapshot
      do {
        restaurantSnapshot = try transaction.getDocument(reference)
      } catch let error as NSError {
        errorPointer?.pointee = error
        return nil
      }

      // Error if the restaurant data in Firestore has somehow changed or is malformed.
      let maybeRestaurant: Restaurant?
      do {
        maybeRestaurant = try restaurantSnapshot.data(as: Restaurant.self)
      } catch {
        errorPointer?.pointee = NSError(domain: "FriendlyEatsErrorDomain", code: 0, userInfo: [
          NSLocalizedDescriptionKey: "Unable to read restaurant at Firestore path: \(reference.path): \(error)",
        ])
        return nil
      }

      guard let restaurant = maybeRestaurant else {
        errorPointer?.pointee = NSError(domain: "FriendlyEatsErrorDomain", code: 0, userInfo: [
          NSLocalizedDescriptionKey: "Missing restaurant at Firestore path: \(reference.path)",
        ])
        return nil
      }

      // Update the restaurant's rating and rating count and post the new review at the
      // same time.
      let newAverage = (Float(restaurant.ratingCount) * restaurant
        .averageRating + Float(review.rating))
        / Float(restaurant.ratingCount + 1)

      do {
        try transaction.setData(from: review, forDocument: newReviewReference)
      } catch let error as NSError {
        errorPointer?.pointee = error
        return nil
      }
      transaction.updateData([
        "numRatings": restaurant.ratingCount + 1,
        "avgRating": newAverage,
      ], forDocument: reference)
      return nil
    }) { object, error in
      if let error = error {
        print(error)
      } else {
        // Pop the review controller on success
        if self.navigationController?.topViewController?
          .isKind(of: NewReviewViewController.self) ?? false {
          self.navigationController?.popViewController(animated: true)
        }
      }
    }
  }