Symfony mock service when test console command - symfony

How to mock some service when test console command. I have some console command, in this command I get some service and I want mock this service
console command
const APP_SATISFACTION_REPORT = 'app:satisfactionrepor';
protected function configure()
{
$this
->setName(self::APP_SATISFACTION_REPORT)
->setDescription('Send Satisfaction Report');
}
/**
* #param InputInterface $input
* #param OutputInterface $output
*/
protected function execute(InputInterface $input, OutputInterface $output)
{
$container = $this->getContainer();
$serviceCompanyRepo = $container->get('app.repository.orm.service_company_repository');
$satisfactionReport = $container->get('app.services.satisfaction_report');
/** #var ServiceCompany $serviceCompany */
foreach ($serviceCompanyRepo->findAll() as $serviceCompany) {
try {
$satisfactionReport->sendReport($serviceCompany);
} catch (\Exception $e) {
$io->warning(sprintf(
'Failed to send satisfaction report for service company with ID %s',
$serviceCompany->getId()
));
}
}
}
and my tests
/** #var Console\Application $application */
protected $application;
protected $container;
/** #var BufferedOutput $output */
protected $output;
/**
* #var ServiceCompanyRepository
*/
private $serviceCompanyRepository;
prepare console command
public function setUp()
{
parent::setUp();
$entityManager = $this->getEntityManager();
$this->serviceCompanyRepository = $entityManager->getRepository(ServiceCompany::class);
static::bootKernel();
$this->container = static::$kernel->getContainer();
$this->application = new Console\Application(static::$kernel);
$this->application->setAutoExit(false);
$master = new SatisfactionReportCommand();
$this->application->add($master);
}
public function setUpMaster() {
$this->output = new BufferedOutput();
$this->application->run(new ArgvInput([
'./bin/console',
SatisfactionReportCommand::APP_SATISFACTION_REPORT,
]), $this->output);
}
public function testGetMasterOutput()
{
$this->loadFixture(ServiceCompany::class);
/** #var ServiceCompany[] $serviceCompanies */
$serviceCompanies = $this->serviceCompanyRepository->findAll();
$this->assertCount(2, $serviceCompanies);
$client = self::createClient();
mock service app.services.satisfaction_report
$service = $this->getMockService($serviceCompanies);
and set it in container
$client->getContainer()->set('app.services.satisfaction_report', $service);
$this->setUpMaster();
$output = $this->output->fetch();
}
protected function getMockService($serviceCompanies)
{
$service = $this->getMockBuilder(SatisfactionReport::class)
->setMethods(['sendReport'])
->disableOriginalConstructor()
->getMock();
$service
->expects($this->exactly(2))
->method('sendReport')
->withConsecutive(
[$serviceCompanies[0]],
[$serviceCompanies[1]]
);
return $service;
}
How to mock app.services.satisfaction_report? Set in container app.services.satisfaction_report not help me

I had same problem but I resolved it.
I have base class:
class TestCase extends WebTestCase
{
/** #var Application */
private $application;
private $mailServiceMock;
protected function setMailService(MailService $mailServiceMock): void
{
$this->mailServiceMock = $mailServiceMock;
}
protected function getApplication(): Application
{
static::bootKernel();
static::$kernel->getContainer()->get('test.client');
$this->setMocks();
$this->application = new Application(static::$kernel);
$this->application->setCatchExceptions(false);
$this->application->setAutoExit(false);
return $this->application;
}
protected function execute(string $action, array $arguments = [], array $inputs = []): CommandTester
{
$tester = (new CommandTester($this->getApplication()->find($action)))->setInputs($inputs);
$tester->execute($arguments);
return $tester;
}
private function setMocks(): void
{
if ($this->mailServiceMock) {
static::$kernel->getContainer()->set('mail', $this->mailServiceMock);
}
}
}
And test class
class SendEmailCommandTest extends TestCase
{
public function testExecuteSendingError(): void
{
$mailServiceMock = $this->getMockBuilder(MailService::class)->disableOriginalConstructor()
->setMethods(['sendEmail'])->getMock();
$mailServiceMock->method('sendEmail')->willThrowException(new \Exception());
$this->setMailService($mailServiceMock);
$tester = $this->execute(SendEmailCommand::COMMAND_NAME, self::NORMAL_PAYLOAD);
$this->assertEquals(SendEmailCommand::STATUS_CODE_EMAIL_SENDING_ERROR, $tester->getStatusCode());
}
}
As you can see I set mail service right after booting kernel.
And here you can see my services.yaml:
services:
mail.command.send.email:
autowire: true
class: App\Command\SendEmailCommand
arguments: ["#logger", "#mail"]
tags:
- {name: console.command, command: "mail:send.email"}

If you create the commands as a service, where the framework injects the services automatically (either autowired, or with an explicit argument list) into a constructor (tip: in the command, call the parent::__construct()), then the test can create whatever mock or other replacement service that matches the parameter typehint (or interface).

here is my example class:
class MainCommandTest extends IntegrationTestCase
{
/**
* #var MainCommand
*/
protected $subject;
/**
* #var Application
*/
protected $application;
/**
* sets test subject
*
* #return void
*/
public function setUp()
{
parent::setUp();
static::bootKernel();
$readStreams = new ReadStreams();
$udpStreamMock = $this->getMockBuilder(UdpStream::class)->disableOriginalConstructor()->setMethods(['readIncomingStreams'])->getMock();
$udpStreamMock->expects($this->once())->method('readIncomingStreams')->willReturn($readStreams);
static::$kernel->getContainer()->set(UdpStream::class, $udpStreamMock);
$application = new Application($this::$kernel);
$this->subject = $this->getService(MainCommand::class);
$application->add( $this->subject);
$this->application = $application;
}
/**
* Tests command in $subject command,
*
* #return void
*/
public function testCommand()
{
$command = $this->application->find( $this->subject->getName());
$commandTester = new CommandTester($command);
$commandTester->execute(
[
'command' => $this->subject->getName()
]
);
$this->stringContains($commandTester->getDisplay(true), 'finished');
$this->assertEquals($commandTester->getStatusCode(), 0);
}
}

Related

How to mock variables in a PHPUnit Coverage Test?

I'm writing PHPUnit tests and running coverage tests. I admit its very difficult to have 100% coverage, however, I'd like to get as close as possible. In a following scenario, how to mock variables in a clause in order to test the code block?
class CalendarClientService
{
/** #var array SCOPES */
public const SCOPES = [Google_Service_Calendar::CALENDAR];
/** #var string ACCESS_TYPE */
public const ACCESS_TYPE = "offline";
/** #var string CALENDAR_ID */
public const CALENDAR_ID = "primary";
/** #var int MAX_RESULTS */
public const MAX_RESULTS = 25;
/** #var string ORDER_BY */
public const ORDER_BY = "startTime";
/** #var bool SINGLE_EVENTS */
public const SINGLE_EVENTS = true;
/** #var string|null TIME_MIN */
public const TIME_MIN = null;
/** #var bool CACHE_TIME_TO_LIVE */
public const CACHE_TIME_TO_LIVE = 604800;
/** #var string */
public string $clientSecretPath = "";
/** #var StorageAdapterFactoryInterface */
protected StorageAdapterFactoryInterface $storageAdapterFactory;
/** #var StorageInterface */
protected StorageInterface $storageInterfaceCache;
/**
* CalendarClientService constructor.
* #param string $clientSecretPath
* #param StorageAdapterFactoryInterface $storageAdapterFactory
* #param StorageInterface $storageInterfaceCache
*/
public function __construct(
string $clientSecretPath,
StorageAdapterFactoryInterface $storageAdapterFactory,
StorageInterface $storageInterfaceCache
) {
$this->clientSecretPath = $clientSecretPath;
$this->storageAdapterFactory = $storageAdapterFactory;
$this->storageInterfaceCache = $storageInterfaceCache;
}
/** #return string */
public function getClientSecretPath()
{
return $this->clientSecretPath;
}
/** #param string $secretFile */
public function setClientSecretPath(string $secretFile)
{
$this->clientSecretPath = $secretFile;
}
/**
* #param array
* #return Google_Service_Calendar_Event
*/
public function getGoogleServiceCalendarEvent($eventData)
{
return new Google_Service_Calendar_Event($eventData);
}
/**
* #param string
* #return Google_Service_Calendar_EventDateTime
*/
public function getGoogleServiceCalendarEventDateTime($dateTime)
{
$eventDateTime = new Google_Service_Calendar_EventDateTime();
$eventDateTime->setDateTime(Carbon::parse($dateTime)->toW3cString());
$eventDateTime->setTimeZone(Carbon::parse($dateTime)->timezone->getName());
return $eventDateTime;
}
/**
* #param Google_Client $client
* #return Events
*/
public function getGoogleServiceCalendarResourceEvents(Google_Client $client)
{
$service = new Google_Service_Calendar($client);
return $service->events;
}
/**
* #param int
* #return array
* #throws Exception
* #throws ExceptionInterface
*/
public function getEventData($id)
{
$client = $this->getClient();
if (!$this->authenticateClient($client)) {
return [
"error" => "authentication",
"url" => filter_var($client->createAuthUrl(), FILTER_SANITIZE_URL),
];
}
$service = $this->getGoogleServiceCalendarResourceEvents($client);
return ["event" => $service->get(self::CALENDAR_ID, $id)];
}
/**
* #return Google_Client
* #throws Exception
*/
public function getClient()
{
$client = new Google_Client();
$client->setApplicationName(Module::MODULE_NAME);
$client->setScopes(self::SCOPES);
$client->setAuthConfig($this->clientSecretPath);
$client->setAccessType(self::ACCESS_TYPE);
return $client;
}
/**
* #param Google_Client $client
* #return bool
* #throws ExceptionInterface
*/
public function authenticateClient(Google_Client $client)
{
if ($this->storageInterfaceCache->hasItem("api_access_token")) {
$accessToken = json_decode($this->storageInterfaceCache->getItem("api_access_token"), true);
if ($accessToken["error"] == "invalid_grant" || empty($accessToken)) {
$this->storageInterfaceCache->removeItem("api_access_token");
} else {
$this->storageInterfaceCache->setItem("api_access_token", json_encode($accessToken));
$client->setAccessToken($accessToken);
}
}
if ($client->isAccessTokenExpired()) {
$tokenValid = false;
if ($client->getRefreshToken()) {
$client->fetchAccessTokenWithRefreshToken($client->getRefreshToken());
$accessToken = $client->getAccessToken();
$this->storageInterfaceCache->setItem("api_access_token", json_encode($accessToken));
$tokenValid = true;
} else {
$helper = new Helper();
if(!$helper->verifyAuthCode($_GET["code"])){
return $tokenValid;
}
$authCode = $_GET["code"];
$accessToken = $client->fetchAccessTokenWithAuthCode($authCode);
if ($accessToken["error"] == "invalid_grant" || empty($accessToken)) {
$this->storageInterfaceCache->removeItem("api_access_token");
} else {
$this->storageInterfaceCache->setItem("api_access_token", json_encode($accessToken));
$client->setAccessToken($accessToken);
$tokenValid = true;
}
}
} else {
$tokenValid = true;
}
return isset($tokenValid) ? $tokenValid : false;
}
I want to test this 6th line from top in authenticateClient method and want to mock this clause $accessToken["error"] == "invalid_grant" || empty($accessToken).
Now how to go about it?
Edit: Here's a test that I've written. Now whatever value I'm mocking in the $this->storageInterfaceCacheMock->method("getItem"), it always returns empty $accessToken. I've also attached the image for better understanding of what's happening and what I want.
public function testGetEventDataReturnsArrayOnSuccessfulAuthenticateClientThroughCache()
{
$this->storageInterfaceCacheMock->method("hasItem")->willReturn(true);
$this->storageInterfaceCacheMock->method("getItem")->willReturn(json_encode('{"access_token":"ya29.a0ARrdaM99pJTf1XzmD1ngxAH3XJud8lvHb0aTaOOABYdfdhsdfgsdfgVD9OoH4heiKoskDF7DMkHj1_aPuWIO5TE14KHJidFf66xwn_pTCkkSow6Kg4lRHwGrNQBQGI8sPlgnFO5U5hJvYdqgxDMHEqw1TER2w","expires_in":3599,"scope":"https:\/\/www.googleapis.com\/auth\/calendar","token_type":"Bearer","created":1637312218,"refresh_token":"1\/\/03psr5omKiljUCgYFDHDGJHGSHSNwF-L9Iraor5zcfe-h3BeCHSFGSDFGDGJHjy4UnEtKj974LXthS5bWexQcjviVGfJsdfGHSHgIrDn6Yk"}'));
$this->assertIsArray($this->calendarClientService->getEventData(1));
}
Another test which isn't performing as per required is mentioned below. (also visible in the screenshot)
public function testAccessTokenIsExpiredAndGotRefreshToken()
{
$this->googleClientMock->method("isAccessTokenExpired")->willReturn(true);
$this->googleClientMock->method("getRefreshToken")->willReturn(true);
$this->googleClientMock->method("fetchAccessTokenWithRefreshToken")->willReturnSelf();
$this->googleClientMock->method("getAccessToken")->willReturnSelf();
$this->assertTrue($this->calendarClientService->authenticateClient($this->googleClientMock));
}
I believe you want json_decode you don't need double encode here:
$this->storageInterfaceCacheMock->method("getItem")->willReturn(json_encode('{"access_token":"...."}'));
just
$this->storageInterfaceCacheMock->method("getItem")->willReturn('{"access_token":"...."}');
Here's how I resolved the issue and got the test to be successful.
I declared a dummy ACCESS_TOKEN as below and then used in the test method.
class CalendarControllerTest extends AbstractApplicationTestCase
{
/** #var string CLIENT_SECRET */
public const CLIENT_SECRET = __DIR__ . "/../_fixtures/config/client_secret.json";
/** #var string CLIENT_SECRET */
public const ACCESS_TOKEN = [
"access_token" => "test-data",
"expires_in" => 3592,
"scope" => "https://www.googleapis.com/auth/calendar",
"token_type" => "Bearer",
"created" => 1640858809,
];
...
...
...
}
public function setUp(): void
{
parent::setUp();
$this->googleClientMock = $this->getMockBuilder(Google_Client::class)
->disableOriginalConstructor()
->onlyMethods(
[
"isAccessTokenExpired",
"setAuthConfig",
"getRefreshToken",
"fetchAccessTokenWithRefreshToken",
"fetchAccessTokenWithAuthCode",
"getAccessToken",
"setAccessToken",
]
)
->getMock();
$this->googleServiceCalendarResourceEventsMock = $this->getMockBuilder(Events::class)
->disableOriginalConstructor()
->onlyMethods(["get"])
->getMock();
$this->googleServiceCalendarEventMock = $this->getMockBuilder(Event::class)
->disableOriginalConstructor()
->getMock();
$this->storageInterfaceCacheMock = $this->getMockForAbstractClass(StorageInterface::class);
$this->container->setAllowOverride(true);
$this->container->setService(Google_Client::class, $this->googleClientMock);
$this->container->setService(Events::class, $this->googleServiceCalendarResourceEventsMock);
$this->container->setService(Event::class, $this->googleServiceCalendarEventMock);
$this->container->setService(StorageInterface::class, $this->storageInterfaceCacheMock);
$this->container->setAllowOverride(true);
$this->googleClientMock->method("setAuthConfig")->willReturn(true);
$this->calendarClientService = $this->container->get("ServiceManager")->get(CalendarClientService::class);
$this->calendarClientService->setClientSecretPath(CalendarControllerTest::CLIENT_SECRET);
}
/** #throws ExceptionInterface */
public function testAccessTokenIsExpiredAndFailureToRefreshTokenWillGenerateNewAccessToken()
{
$this->calendarClientService->setAuthCode(CalendarControllerTest::DEFAULT_TESTING_VALUE);
$this->googleClientMock->method("isAccessTokenExpired")->willReturn(true);
$this->googleClientMock->method("getRefreshToken")->willReturn(false);
$this->googleClientMock->method("fetchAccessTokenWithAuthCode")->willReturn(
CalendarControllerTest::ACCESS_TOKEN
);
$this->storageInterfaceCacheMock->method("setItem")->willReturn(true);
$this->googleClientMock->method("setAccessToken")->willReturnSelf();
$this->assertTrue($this->calendarClientService->authenticateClient($this->googleClientMock));
}

PHPUnit object initialized in setUp() becomes null after 1st test

I am new to PHPunit and while learning it with sample classes, I am getting error. The error is that, the Object $this->sysman, that is initialized in setUp() becomes null after execution of the 1st test. Below is code, which I am trying. Please let me know what is mistake here. Thanks.
class PersonTest extends TestCase {
/** #var SysManService $sysman */
protected $sysman;
protected $personModel;
public function setUp(){
/** #var Adapter $adapter */
$adapter = $this->prophesize(Adapter::class)->reveal();
/** #var LoggerService $logger */
$logger = $this->prophesize(LoggerService::class)->reveal();
/** #var ContainerInterface $container */
$container = $this->prophesize(ContainerInterface::class);
$config = (array)$container->get('config');
$this->sysman = new SysManService($adapter, $logger, $config);
//$sysman = new SysManService($adapter, $logger, $config);
$this->personModel = new Person($this->sysman);
}
protected function tearDown(){ }
public function testPropertyUserNameExists() {
$this->assertObjectHasAttribute('userName', $this->personModel);
}
public function testPropertyPasswordExists() {
$this->assertObjectHasAttribute('password', $this->personModel);
}}

How to test dependency injection with PHPUnit on symfony 4

In a symfony 4 project, many services/controllers need log.
Trying to use the advantage of traits & autowire options given by symfony, I created a loggerTrait that will be passed to the different services.
namespace App\Helper;
use Psr\Log\LoggerInterface;
use Psr\Log\LogLevel;
trait LoggerTrait
{
/** #var LoggerInterface */
private $logger;
/** #var array */
private $context = [];
/**
* #return LoggerInterface
*/
public function getLogger(): LoggerInterface
{
return $this->logger;
}
/**
* #required
*
* #param LoggerInterface|null $logger
*/
public function setLogger(?LoggerInterface $logger): void
{
$this->logger = $logger;
}
public function logDebug(string $message, array $context = []): void
{
$this->log(LogLevel::DEBUG, $message, $context);
}
...
}
(inspired by symfonycasts.com)
A service will be using this trait
namespace App\Service;
use App\Helper\LoggerTrait;
class BaseService
{
use LoggerTrait;
/** #var string */
private $name;
public function __construct(string $serviceName)
{
$this->name = $serviceName;
}
public function logName()
{
$this->logInfo('Name of the service', ['name' => $this->name]);
}
}
It works perfectly but I couldn't succeed to test it.
I tried to extend KernelTestCase in my test to mock an loggerInterface but I receive Symfony\Component\DependencyInjection\Exception\InvalidArgumentException: The "Psr\Log\LoggerInterface" service is private, you cannot replace it which make perfect sens.
Here my test:
namespace App\Tests\Service;
use App\Service\BaseService;
use Psr\Log\LoggerInterface;
use Symfony\Bundle\FrameworkBundle\Test\KernelTestCase;
class BaseServiceTest extends KernelTestCase
{
private function loggerMock()
{
return $this->createMock(LoggerInterface::class);
}
protected function setUp()
{
self::bootKernel();
}
/**
* #test
* #covers ::logName
*/
public function itShouldLogName()
{
// returns the real and unchanged service container
$container = self::$kernel->getContainer();
// gets the special container that allows fetching private services
$container = self::$container;
$loggerMock = $this->loggerMock();
$loggerMock->expect(self::once())
->method('log')
->with('info', 'Name of the service', ['name' => 'service_test']);
$this->logger = $container->set(LoggerInterface::class, $loggerMock);
$baseService = new BaseService('service_test');
var_dump($baseService->getLogger());
}
}
Is there a solution to test such a logger inside the service ?
You can override the service to be public (only for the test environment) in your config_test.yml as follows:
services:
Psr\Log\LoggerInterface:
public: true
This is commonly done for testing private services.

Create records in separate table when user registers new account

Im creating a WebBrowser game with Symfony2. What I want to achieve is:
I have a table with Users. When new user registers in the game, new record is added to table fos_user. When new user is registered I also want to put records in the table that stores users resources in the game with starting quantity.
I have read about event listeners but I'm not sure if they are the best way to resolve my problem.
This is the Entity that holds User, type of material and its quantity
/**
* #var int
*
* #ORM\Column(name="quantity", type="bigint")
*/
private $quantity;
/*
* connection material->MaterialStock<-User
*/
/**
*#ORM\ManyToOne(targetEntity="Material", inversedBy="userMaterial")
*
*/
private $material;
/**
*
* #ORM\ManyToOne(targetEntity="User", inversedBy="userMaterial")
*/
private $user;
function getId() {
return $this->id;
}
function getQuantity() {
return $this->quantity;
}
function getMaterial() {
return $this->material;
}
function getUser() {
return $this->user;
}
function setQuantity($quantity) {
$this->quantity = $quantity;
}
function setMaterial($material) {
$this->material = $material;
}
function setUser($user) {
$this->user = $user;
}
}
User entity looks like this
<?php
// src/AppBundle/Entity/User.php
namespace FactoryBundle\Entity;
use FOS\UserBundle\Model\User as BaseUser;
use Doctrine\ORM\Mapping as ORM;
use FactoryBundle\Entity\Factory;
use Doctrine\Common\Collections\ArrayCollection;
/**
* #ORM\Entity
* #ORM\Table(name="fos_user")
*/
class User extends BaseUser
{
/**
* #ORM\Id
* #ORM\Column(type="integer")
* #ORM\GeneratedValue(strategy="AUTO")
*
*/
protected $id;
public function __construct()
{
parent::__construct();
$this->productionOrders = new ArrayCollection();
}
/**
* #ORM\OneToOne(targetEntity="Factory", mappedBy="user")
*/
private $factory;
/*
* connecting User->materialStock<-Material
*/
/**
*
* #ORM\OneToMany(targetEntity="MaterialStock", mappedBy="user")
*/
private $userMaterial;
/**
* #ORM\OneToMany(targetEntity="ProductionOrders", mappedBy="user")
*/
private $productionOrders;
/** #ORM\OneToMany(targetEntity="ToyStock", mappedBy="user") */
private $userToyStock;
function getId() {
return $this->id;
}
function getFactory() {
return $this->factory;
}
function getUserMaterial() {
return $this->userMaterial;
}
function getProductionOrders() {
return $this->productionOrders;
}
function getUserToyStock() {
return $this->userToyStock;
}
function setId($id) {
$this->id = $id;
}
function setFactory($factory) {
$this->factory = $factory;
}
function setUserMaterial($userMaterial) {
$this->userMaterial = $userMaterial;
}
function setProductionOrders($productionOrders) {
$this->productionOrders = $productionOrders;
}
function setUserToyStock($userToyStock) {
$this->userToyStock = $userToyStock;
}
}
You can use an event subscriber.
<?php
namespace ...;
use FOS\UserBundle\FOSUserEvents;
use FOS\UserBundle\Event\FilterUserResponseEvent;
use Steora\Api\UserBundle\Entity\User;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use ...\EntityThatHoldsUserTypeOfMaterialAndQuantity;
/**
* ...
*/
class RegistrationCompletionListener implements EventSubscriberInterface
{
/** #var EntityManager */
private $em;
/**
* #param EntityManager $em
*/
public function __construct(EntityManager $em)
{
$this->em = $em;
}
/**
* {#inheritdoc}
*/
public static function getSubscribedEvents()
{
return array(
FOSUserEvents::REGISTRATION_COMPLETED => 'onRegistrationCompletionSuccess',
);
}
/**
* #param FilterUserResponseEvent $event
*/
public function onRegistrationCompletionSuccess(FilterUserResponseEvent $event)
{
// you can modify response here, but you can remove this line if there is no need to touch response...
$response = $event->getResponse();
$user = $event->getUser();
$entityThatHoldsUserTypeOfMaterialAndQuantity = new EntityThatHoldsUserTypeOfMaterialAndQuantity();
$entityThatHoldsUserTypeOfMaterialAndQuantity->setUser($user);
$entityThatHoldsUserTypeOfMaterialAndQuantity->setQuantity(...);
...
$this->em->persist($entityThatHoldsUserTypeOfMaterialAndQuantity);
$this->em->flush();
}
}
Register your service in service.yml
services:
...
steora.api.user.registration_confirmation:
class: YourBundle\..\RegistrationCompletionListener
arguments: ['#doctrine.orm.default_entity_manager']
tags:
- { name: kernel.event_subscriber }
So, you are listening for some event, and when that event happens, you do stuff that you need :)
Here you can find more events, maybe some other than FOSUserEvents::REGISTRATION_COMPLETED is more suitable for you: https://github.com/FriendsOfSymfony/FOSUserBundle/blob/master/FOSUserEvents.php
Here is an example from the official docs: http://symfony.com/doc/current/bundles/FOSUserBundle/controller_events.html
This is workflow:
1) A user is filling a registration form and submits his data.
2) If the form is valid, this is what happens:
// friendsofsymfony/user-bundle/Controller/RegistrationController.php
if ($form->isSubmitted()) {
if ($form->isValid()) {
$event = new FormEvent($form, $request);
$dispatcher->dispatch(FOSUserEvents::REGISTRATION_SUCCESS, $event);
$userManager->updateUser($user);
if (null === $response = $event->getResponse()) {
$url = $this->generateUrl('fos_user_registration_confirmed');
$response = new RedirectResponse($url);
}
// This is event you are listening for!!!!
$dispatcher->dispatch(FOSUserEvents::REGISTRATION_COMPLETED, new FilterUserResponseEvent($user, $request, $response));
return $response;
}
$event = new FormEvent($form, $request);
$dispatcher->dispatch(FOSUserEvents::REGISTRATION_FAILURE, $event);
if (null !== $response = $event->getResponse()) {
return $response;
}
}
3) Your listener reacts on event, and in onRegistrationCompletionSuccess() you do your stuff, and after that everything continues as usual :)
Matko Đipalo
Thank you for your answer. If I understood you correctly the workflow of your approach is:
FOSUser:RegistrationController.php creates an event when registration is completed
$dispatcher->dispatch(FOSUserEvents::REGISTRATION_COMPLETED, new FilterUserResponseEvent($user, $request, $response));
in your class RegistrationCompletionListener in line:
public static function getSubscribedEvents()
{
return array(
FOSUserEvents::REGISTRATION_COMPLETED => 'onRegistrationCompletionSuccess',
);
}enter code here
Im specifieing to what events I want my app to listen too and on line:
public function onRegistrationCompletionSuccess(FilterUserResponseEvent $event)
{
$response = $event->getResponse();
//... make needed actions
$this->yourDependencies->doSomeStufff()...
}
I can tell me script what to do when that event will accour. In my case get the user object and create for him records in database.

method data provider executes before setup

i have test class like this
class CallTest extends WebTestCase
{
/** #var \Doctrine\Common\DataFixtures\Executor\AbstractExecutor */
protected $executor;
public function setUp()
{
$this->executor = $this->loadFixtures(array('Tests\Fixtures\LoadCallData'));
}
/**
* #dataProvider callProvider
*/
public function testCall($service, $token, $fileId, $phone, $callTime)
{
// some code for testing
}
/**
* Данные для проверки
* #return array
*/
public function callProvider()
{
$devices = $this->devicesProvider();
// providing some data
return array(.....);
}
public function devicesProvider()
{
return array_map(
function ($device) use($service) {
return array($service, $device);
},
$devices
);
}
}
problem is that setUp method not rans

Resources