Creating and Using Services in Symfony

Services are little useful bricks that can be used almost everywhere in your Symfony application. If an object needs to be used in various Controllers then it should be written as a Service. In this short tutorial I am going to describe a simple implementation of Services, explain how to access the entity manager and other Symfony components inside a Service, and show a few examples of how Services can be called and used in Controllers and in Commands.

Aims of this tutorial :

  • Create a custom Service class
  • Inject Services / Other into a Service
  • Call and use the Service inside a Controller
  • Call and use the Service inside a Command

Resources :

Symfony version : 3.2 (Services have become even more flexible in Symfony 3.4 (LTS), but the majority of this tutorial remains valid)

Let’s get started !

Part 1 : Create a custom Service class

<?php
namespace Playgound\CookiejarBundle\Services;

class CookieTools
{
    public function giveACookie()
    {
        return 'Keep calm and have a cookie.';
    }
}

In order to use the Service, we need to register it with Symfony :

# app/config/services.yml
services:
    cookiejar_bundle.cookie_tools:          # any name you want, just make it unique
        class: Playground\CookiejarBundle\Services\CookieTools  # the class
        arguments: []

In this example, the Service is registered in the main services.yml file. But if a Service is only used inside a single bundle, it can also be registered in the services.yml file of that bundle.

Now the Service is ready to be used !

Part 2 : Inject Services / Other into a Service

Now supposing we need to fetch some data from the database, or maybe we need to translate something or generate a route. We would then need to have access to the Entity Manager and to the Container. In order to achieve that, we can use the __construct() method to pass those things to the Service.

The Service class becomes :

<?php
namespace Playground\CookiejarBundle\Services;

use Doctrine\ORM\EntityManager;
use Symfony\Component\DependencyInjection\Container;

use Playground\CookiejarBundle\Entity;
use Playground\CookiejarBundle\Cookie;

class CookieTools
{
    protected $em;
    private $container;

    public function __construct(EntityManager $entityManager, Container $container)
    {
	    $this->em = $entityManager;
	    $this->container = $container;
    }

    public function giveACookie($user = null)
    {
        // Get the translator
		$translator = $this->container->get('translator');
		// Get a repository
		$cookieRep = $this->em->getRepository('PlaygroundCookieJarBundle:Cookie');

        // If the user is not null, get its favorite cookie
        if ($user !== null)
        {
            $cookie = $cookieRep->findOneBy(array(
                'favorite'   =>  $user    
            ));
            
            if ($cookie !== null)
            {
                // Translate the message for the user and include the cookie name
                $msg = $translator->trans(
                    'cookie_for_you', 
                    array("cookie"=>$cookie->getName()), 
                    'cookie_translations');
                    
                // Send the message
                return $msg;
            }
        }
        
        // Default
        return null;
	}
}

Next we need to include the __construct() arguments in the Service registration also:

# app/config/services.yml
services:
    cookiejar_bundle.cookie_tools:
        class: Playground\CookiejarBundle\Services\CookieTools
        arguments: ["@doctrine.orm.entity_manager", "@service_container"]

Of course, custom services can also be injected in the same way.

Part 3 : Call and use the Service inside a Controller

Using the Service inside a Controller is really simple :

<?php
// Inside the Controller, call the service using the exact name used in its regiostration (services.yml)
$cookieTools = $this->get('cookiejar_bundle.cookie_tools');

// Use any function inside the Service like this :
$cookieForUser = $cookieTools->giveACookie($user);

Part 4 : Call and use the Service inside a Command

Using the Service inside a Command is like using it inside a Controller. The only difference is that the Command needs access to the Container in order to call the Service :

<?php
namespace Playground\CookiejarBundle\Command;

use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;

use Symfony\Bundle\FrameworkBundle\Command\ContainerAwareCommand;

class CreateInvoiceableCommand extends ContainerAwareCommand
{
	protected function configure ()
	{
		// Name
		$this->setName('cookie:giveCookieToEveryone');

		// Description
		$this->setDescription("Gives its favorite cookie to every user.");

		// Help
		$this->setHelp("Call this command from Cron task every day at midnight");

	}

	public function execute (InputInterface $input, OutputInterface $output)
	{
	    // Get the Service
		$cookieTools = $this->getContainer()->get('cookiejar_bundle.cookie_tools');
	
	    // Get the Entity Manager
	    $entityManager = $this->getContainer()->get('doctrine')->getEntityManager();
	    
	    // Get all the users
	    $users = $entityManager->getRepository('SecurityBundle:User')->findAll();
	    
	    // Give them cookies
	    $cookiesForAll = array();
	    foreach ($users as $user)
	    {
	        // Get the user's favorite cookie using the Service
	        $cookie = $cookieTools->giveACookie($user);
	        
	        if ($cookie !== null)
	        {
	            $cookiesForAll[]['user'] = $user->getId();
	            $cookiesForAll[]['cookie'] = $cookie;
	        }
	    }

		return $cookiesForAll;
	}
}

That’s all 😉

Have fun and have a cookie

Leave a Reply

This site uses Akismet to reduce spam. Learn how your comment data is processed.