Injecting Configuration and Services, and Using Interfaces

Video loading...

  • 0:00
  • 0:02
    Configuration and Services, and Using Interfaces
  • 0:07
    Leanna Pelham
  • 0:09
    We've already created our first service
  • 0:11
    and used dependency injection.
  • 0:13
    We're even closer to getting this money out.
  • 0:16
    One problem with the FriendHarvester is that we've
  • 0:19
    hard-coded the SMTP configuration inside of it.
  • 0:22
    What if we wanted to reuse this class
  • 0:24
    with a different configuration?
  • 0:26
    Or what if our beta and production setups use different SMTP servers?
  • 0:31
    Right now, both are impossible.
  • 0:33
    When we realized that FriendHarvester needs the PDO object,
  • 0:36
    we injected it via the constructor.
  • 0:39
    The same applies to configuration.
  • 0:41
    Add a second constructor argument, which
  • 0:44
    will be an array of smtpConfig and update the code to use it.
  • 1:07
    Back in app.php, pass the array when creating FriendHarvester.
  • 1:18
    When we try it, it still works.
  • 1:23
    Our class is more flexible now.
  • 1:25
    But let's level up again.
  • 1:28
    We can now configure the FriendHarvester with different SMTP
  • 1:31
    settings, but what if we wanted to change how mails are sent entirely,
  • 1:35
    like from SMTP to sendmail?
  • 1:38
    And what if we needed to use the mailer
  • 1:39
    object somewhere else in our app?
  • 1:42
    Right now, we would need to create it anywhere we need it
  • 1:45
    since it's buried inside FriendHarvester.
  • 1:47
    In fact, FriendHarvester doesn't really
  • 1:49
    care how we're sending emails.
  • 1:52
    It only cares that it has an SmtpMailer
  • 1:54
    object so that it can call sendMessage.
  • 1:57
    So like with the PDO object, it's a dependency.
  • 2:01
    Refactor our class to pass in the whole SmtpMailer
  • 2:04
    object instead of just its configuration.
  • 2:23
    Update app.php to create the mailer object.
  • 2:42
    Try it out to make sure it still works.
  • 2:45
    We would hate for our friends to miss this opportunity.
  • 2:49
    Once again, this makes the FriendHarvester even more flexible
  • 2:52
    and readable, and will also make reusing the mailer possible.
  • 2:56
    As a general rule, it's almost always better
  • 2:59
    to inject a service into another than to create it internally.
  • 3:03
    When you're in a service, think twice about using the new keyword,
  • 3:06
    unless you're instantiating a simple object that exists just
  • 3:09
    to hold data instead of doing some job.
  • 3:13
    One thing we've neglected to do is type
  • 3:15
    in our two constructor arguments.
  • 3:17
    Let's do it now.
  • 3:19
    This is totally optional but has a bunch of benefits.
  • 3:23
    First, if you pass something else in,
  • 3:25
    you'll get a much clearer error message.
  • 3:27
    Second, it documents the class even further.
  • 3:31
    A developer now knows exactly what method
  • 3:33
    she can call on these objects.
  • 3:36
    And third, if you use an IDE, this gives you auto-completion.
  • 3:40
    Type-hinting is optional, but I highly recommend it.
  • 3:44
    Right now, we're injecting an SmtpMailer,
  • 3:47
    but in reality, FriendHarvester only cares
  • 3:50
    that the mailer has the sendMessage method on it.
  • 3:52
    But even if we had another class with an identical method--
  • 3:56
    like sendmail mailer, for example-- we
  • 3:58
    couldn't use it because of the specific type-hint.
  • 4:02
    To make this more awesome, create a new MailerInterface.php file which
  • 4:07
    holds an interface with the single send method
  • 4:09
    that all the mailers must have.
  • 4:25
    Update SmtpMailer mailer to implement the interface
  • 4:28
    and change the type-hint in FriendHarvester as well.
  • 4:47
    When you're finished, try the application again.
  • 4:52
    Everything should still work just fine, and with any luck,
  • 4:55
    you'll find a place for all of that annoying money.
  • 4:59
    Just like with every step so far, this has a few great advantages.
  • 5:05
    First, FriendHarvester is more flexible
  • 5:07
    since it now accepts any object that implements MailerInterface.
  • 5:11
    Second, it documents our code a bit more.
  • 5:14
    It's clear now exactly what small functionality
  • 5:17
    FriendHarvester actually needs.
  • 5:20
    Finally, in SmtpMailer, the fact that it implements an interface
  • 5:24
    with the sendMessage method tells us that this method
  • 5:27
    is particularly important.
  • 5:29
    The class could have other methods, but sendMessage is probably
  • 5:32
    an especially important one to focus on.

Injecting Configuration and Services, and Using Interfaces


We’ve already created our first service and used dependency injection, but one problem with the FriendHarvester is that we’ve hardcoded the SMTP configuration inside of it. What if we wanted to re-use this class with a different configuration? Or what if our beta and production setups use different SMTP servers? Right now, both are impossible! In this tutorial we're going to see how we can also inject configuration or an entire service. In the end we're going to inject the entire SmtpMailer object and build an interface for it. Through this process we'll make our code more flexible, since it will be able to accept any object that implements MailerInterface.

Log in or sign up to download companion files.
Additional resources: 

To learn how to apply these concepts in Drupal 8 module development, check out the Module Development Essentials series, starting with Understand the Service Container.