DEV Community

Curtly Critchlow
Curtly Critchlow

Posted on • Updated on

#100DaysOfCodeChallenge -Crop Management Information System- Day 2

Recap

On Day 1 I created the FarmerServiceModel that functions as the Dart Equivalent of the Famer cloud firestore document. On Day 0 I mentioned I'm using the gskinner MVC+S architecture and shared screenshots of the work I have already completed before starting the challenge.

Overview

Today I created the FarmerService() class and the AddFarmerCommand() class. These command is responsible for the S and C respectively for the MCV + S architecture. S for service and C for controller.

Data for this application is stored in cloud firestore. In brief, cloud firestore is a nosql database that stores data in documents. Documents are stored in collections. If you are familiar with sql database you can think of a collection as a sql table (it's more like a list of documents) and documents are like sql table rows (it's more like a glorified Dart Map). You can read more about cloud firestore here.

Going Deeper

Let us take a deep dive into today's progress.

FarmerService Class

The FarmerService() class is responsible for making all network request to cloud firestore Farmers collection and Farmer Document. These request include the standard CRUD related (Create, Read, Update, Delete) request. This class is the bridge between the application and cloud firestore Farmers collection.

The main benefit of having all Farmer related network request in the same class is to improve code readability and maintainability. Think about it, regardless of how big my application gets, the future me knows that any Farmer related network request is handled by the FarmerService() class.

This class has two key features so far; the Farmer Reference variable and the Add Farmer method. More farmer network methods will be added to this class as the application grows.

Farmer Reference Variable

class FarmerService {
  final farmerRef =
      FirebaseFirestore.instance.collection('farmers').withConverter(
            fromFirestore: (snapshot, _) =>
                FarmerServiceModel.fromJson(snapshot.data()!),
            toFirestore: (farmerModel, _) => farmerModel.toJson(),
          );
  ...
}
Enter fullscreen mode Exit fullscreen mode

farmerRef is the main variable in the FarmerService() class. It stores a Collection Reference to the Farmers collection. The FarmerServiceModel that was created on Day 1 is used thanks to the withConverter() method. The combination of the two make the farmer document type safe when the CRUD network request are made. You can read more about this here

Add Farmer Method

class FarmerService {
...

  Future<DocumentReference<FarmerServiceModel>> addFarmer({
    required FarmerServiceModel farmerServiceModel,
  }) async {
    return farmerRef
        .add(farmerServiceModel)
        .then((value) => value)
        .catchError((error) {
      print(error.toString());
    });
  }
}
Enter fullscreen mode Exit fullscreen mode

The AddFarmer() method receive a FarmerServiceModel() instance from the AddFarmer().run() command (more on this later) and call the farmerRef.add(farmerServiceModel) method.

This method sends the farmerServiceModel data to cloud firestore farmers collection as a Document.

FarmerService class full code

class FarmerService {
  final farmerRef =
      FirebaseFirestore.instance.collection('farmers').withConverter(
            fromFirestore: (snapshot, _) =>
                FarmerServiceModel.fromJson(snapshot.data()!),
            toFirestore: (farmerModel, _) => farmerModel.toJson(),
          );

  Future<DocumentReference<FarmerServiceModel>> addFarmer({
    required FarmerServiceModel farmerServiceModel,
  }) async {
    return farmerRef
        .add(farmerServiceModel)
        .then((value) => value)
        .catchError((error) {
      print(error.toString());
    });
  }
}
Enter fullscreen mode Exit fullscreen mode

Thanks to the withConverter method It only takes 18 lines of code to create a Farmer Document in cloud firestore.

Add Farmer Command

/// This class is responsible for farmer registration.
class AddFarmerCommand extends BaseCommand {
  AddFarmerCommand(BuildContext c) : super(c);

  /// Calls FarmerService.addFarmer method
  ///
  /// Recieves farmer data and buildcontext from widget and pass it to the farmerService.addFarmer method.
  Future<bool> run({
    required FarmerServiceModel farmerServiceModel,
    required BuildContext context,
  }) async {
    bool farmerAddedSuccess = false;

    await farmerService
        .addFarmer(farmerServiceModel: farmerServiceModel)
        .then((value) => farmerAddedSuccess = true);
    return farmerAddedSuccess;
  }
}
Enter fullscreen mode Exit fullscreen mode

The only method in this class is run(). This method will pass an instance of the FarmerServiceModel() to the FarmerService().addFarmer method.

Wrap up

The general idea is that the AddFarmerScreen() widget (not created as yet) job is to focus on layout and populating an instance of the FarmerServiceModel with user input. In the next post, I will be showing you how these two job will be separated into the LayoutView and the Controller.

The AddFarmercommand().run() only job is to pass an instance of the FarmerServiceModel() to the FarmerService.addFarmer() method. The instance is received from the AddFarmerScreen() controller.

The FarmerService.addFarmer() method will make the network request to cloud firestore where the FarmerServiceModel() instance will be stored as a Farmers collection document.

Connect with me

Thank you for reading my blog. Feel free to subscribe below to join me on the #100DaysOfCodeChallenge or connect with me on LinkedIn and Twitter.

Top comments (2)

Collapse
 
Sloan, the sloth mascot
Comment deleted
Collapse
 
grahamthedev profile image
GrahamTheDev

Stop spamming irrelevant links to your articles.

50 comments almost identical added today, whatever bot you designed disable it, DEV.to is not the place for this.