24
#100DaysOfCodeChallenge -Crop Management Information System- Day 2
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.
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.
Let us take a deep dive into today's progress.
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.
class FarmerService {
final farmerRef =
FirebaseFirestore.instance.collection('farmers').withConverter(
fromFirestore: (snapshot, _) =>
FarmerServiceModel.fromJson(snapshot.data()!),
toFirestore: (farmerModel, _) => farmerModel.toJson(),
);
...
}
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
class FarmerService {
...
Future<DocumentReference<FarmerServiceModel>> addFarmer({
required FarmerServiceModel farmerServiceModel,
}) async {
return farmerRef
.add(farmerServiceModel)
.then((value) => value)
.catchError((error) {
print(error.toString());
});
}
}
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.
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());
});
}
}
Thanks to the withConverter
method It only takes 18 lines of code to create a Farmer Document in cloud firestore.
/// 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;
}
}
The only method in this class is run()
. This method will pass an instance of the FarmerServiceModel()
to the FarmerService().addFarmer
method.
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.
24