Сервисы в Symfony: Создание и Использование

Сервисы — это маленькие полезные кирпичики, которые можно использовать почти везде в вашем приложении Symfony. Если объект нужно использовать в различных контроллерах, его следует записать как сервис(service). В этом кратком руководстве разберем простую реализацию Services, объясним, как получить доступ к диспетчеру сущностей и другим компонентам Symfony внутри Сервиса, и показать несколько примеров того, как Сервисы можно вызывать и использовать в Контроллерах и в Командах.

Создание пользовательского класса сервиса

<?php
namespace MyApp\MyAppBundle\Services;

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

Чтобы использовать Сервис, нам нужно зарегистрировать его в Symfony:

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

В этом примере Сервис зарегистрирован в основном файле services.yml. Но если Сервис используется только внутри одного пакета, его также можно зарегистрировать в файле services.yml этого пакета. Теперь Сервис готов к использованию!

Внедрение сервисов в другой в сервис

Теперь предположим, что нам нужно получить какие-то данные из базы данных, или, может быть, нам нужно что-то перевести или сгенерировать маршрут. Затем нам потребуется доступ к диспетчеру сущностей и к контейнеру. Для этого мы можем использовать метод __construct() для передачи этих вещей в сервис.

Класс сервиса:

<?php
namespace MyApp\MyAppBundle\Services;

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

use MyApp\MyAppBundle\Entity;
use MyApp\MyAppBundle\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('MyAppBundle: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;
   }
}

Далее нам нужно также включить аргументы __construct() в регистрацию сервиса:

# app/config/services.yml
services:
   myapp_bundle.cookie_tools:
       class: MyApp\MyAppBundle\Services\CookieTools
       arguments: ["@doctrine.orm.entity_manager", "@service_container"]

Конечно, пользовательские сервисы также могут быть внедрены таким же образом.

Вызов и использование сервиса внутри контроллера

Использование службы внутри контроллера очень просто:

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

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

Вызов и использование сервиса внутри команды

Использование сервиса внутри команды похоже на ее использование внутри контроллера. Единственное отличие состоит в том, что Команде нужен доступ к Контейнеру для вызова Сервиса:

<?php
namespace MyApp\MyAppBundle\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('myapp_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;
   }
}