Variable No Longer Exists after Creating Subrequest in Silex (Symfony2) - symfony

I have this issue where I'm attempting to create a subrequest in Silex and basically forward my parameters to another controllers. Exhibit A is broken below (after attempts to refactor), and Exhibit B, the original version, works:
Exhibit A ($this->app is lost after creating the request):
class EntriesController {
private $app;
private $req;
public function __construct($app, $req) {
$this->app = $app;
$this->req = $req;
}
public function updateAction() {
//...
//$url defined here (eyesore-ingly long, so not shown)
$subRequest = Request::create($url, 'GET', $params, $this->req->cookies->all(), array(), $this->req->server->all());
//$this->app **no longer** exists here
return $this->app->handle($subRequest, HttpKernelInterface::SUB_REQUEST);
}
}
EntriesController instance is created below:
class AppControllerProvider implements ControllerProviderInterface {
public function connect(Application $app) {
$controllers = $app['controllers_factory'];
//...
$controllers->patch('/edit', function (Request $req) use ($app) {
$entriesCtrl = new \EntriesController($app, $req);
return $entriesCtrl->updateAction();
});
//...
}
Exhibit B (works just fine):
class AppControllerProvider implements ControllerProviderInterface {
public function connect(Application $app) {
$controllers = $app['controllers_factory'];
$controllers->patch('/edit', function (Request $req) use ($app) {
//...
//$url defined here
$subRequest = Request::create($url, 'GET', $params, $this->req->cookies->all(), array(), $this->req->server->all());
return $this->app->handle($subRequest, HttpKernelInterface::SUB_REQUEST);
}
//...
});
I basically just reorganized the logic from Exhibit B's 'PATCH' /edit method body into a controller class, and I passed the Silex Application instance $app to a new instance of the controller class.

The only difference between Exhibit A and Exhibit B as far as I can tell is that you instantiate a controller object in the path method callback. Maybe there is something wrong with how this controller is setup or a namespace issue? Shootin' in the dark here.
I can confirm that in my silex application the following code does not produce a null $app container:
GlobalControllerProvider.php
<?php
namespace Dev\Pub\Provider\Controller;
use Silex\Application;
use Silex\ControllerProviderInterface;
use Symfony\Component\HttpFoundation\Request;
class GlobalControllerProvider implements ControllerProviderInterface
{
public function connect(Application $app)
{
$controllers = $app['controllers_factory'];
$controllers
->get('/', 'Dev\Pub\Controller\GlobalController::indexAction')
->bind('homepage')
;
$controllers
->patch('/edit', function (Request $req) use ($app) {
$entriesCtrl = new \Dev\Pub\Controller\GlobalController();
return $entriesCtrl->updateAction($app, $req);
});
return $controllers;
}
}
GlobalController.php
<?php
namespace Dev\Pub\Controller;
use Silex\Application;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpKernel\HttpKernelInterface;
class GlobalController
{
public function indexAction(Application $app, Request $request)
{
return new Response($app['twig']->render('index.html.twig'));
}
public function updateAction(Application $app, Request $request)
{
$url = 'http://silex.local/index_dev.php/';
$params = array();
$subRequest = Request::create($url, 'GET', $params, $request->cookies->all(), array(), $request->server->all());
// outputs: 'Silex\Application'
error_log(print_r(get_class($app),1).' '.__FILE__.' '.__LINE__,0);
// outputs: 1
error_log(print_r(is_object($app),1).' '.__FILE__.' '.__LINE__,0);
return $app->handle($subRequest, HttpKernelInterface::SUB_REQUEST);
}
}
index.main.js
$(function(){
console.log('index.main.js');
$.ajax({
url: "http://silex.local/index_dev.php/edit",
method: "PATCH"
}).done(function( data ) {
console.log(data);
}).fail(function( data ) {
console.log(data);
});
});

Related

Phpunit testing callback functions when passing them to a stub method

Here is the method to test.
public function performPoolRequest(RecreationRequestsCollection $requests): RecreatedPaymentsPoolReading
{
$count_request = count($requests);
if($count_request) {
$pool_recreate_payments = new RecreatedPaymentsPool();
$this->http_client->sendPoolRequest(
$this->generateRequests($requests),
$count_request,
function (ResponseInterface $response, $index) use ($requests, $pool_recreate_payments) {
$this->successHandler($response, $requests, $index, $pool_recreate_payments);
},
function (BadResponseException $reason, $index) use ($requests, $pool_recreate_payments) {
$this->failureHandler($reason, $requests, $index, $pool_recreate_payments);
}
);
return $pool_recreate_payments;
} else {
throw new PoolRequestException('Incorrect amount of requests: ' . $count_request);
}
}
Difficulties arose with this piece of code:
$this->http_client->sendPoolRequest(
$this->generateRequests($requests),
$count_request,
function (ResponseInterface $response, $index) use ($requests, $pool_recreate_payments) {
$this->successHandler($response, $requests, $index, $pool_recreate_payments);
},
function (BadResponseException $reason, $index) use ($requests, $pool_recreate_payments) {
$this->failureHandler($reason, $requests, $index, $pool_recreate_payments);
}
);
I made a mock object $this->http_client
But I don't know how to test methods in the argumets ($this->successHandler, $this->failureHandler, this->generateRequests($requests)) that are sent to the method sendPoolRequest.
All of these methods are protected. I understand how to test them using a reflection object, but I want to know if there is an option to test them within a single test by checking the values in $ pool_recreate_payments.
You have to fake what the http client is doing in some way. That means: actually calling the callback functions. While it might be possible to do that with a PHPUnit mock object, writing own test doubles is often easier.
Here are a few examples to get you started.
public function testAllFailing()
{
$client = new class implements HttpClient {
public function sendPoolRequest(array $requests, int $numRequests, callable $successHandler, callable $errorHandler)
{
foreach ($requests as $index => $request) {
$errorHandler(new BadResponseException(/*...*/), $index);
}
}
};
$myService = new MyService($client);
$result = $myService->performPoolRequest(/*...*/);
self::assertEquals(/*...*/, $result);
}
public function testAllSucceeding()
{
$client = new class implements HttpClient {
public function sendPoolRequest(array $requests, int $numRequests, callable $successHandler, callable $errorHandler)
{
foreach ($requests as $index => $request) {
$successHandler(new Response(/*...*/), $index);
}
}
};
$myService = new MyService($client);
$result = $myService->performPoolRequest(/*...*/);
self::assertEquals(/*...*/, $result);
}
public function testEveryOtherFails()
{
$client = new class implements HttpClient {
public function sendPoolRequest(array $requests, int $numRequests, callable $successHandler, callable $errorHandler)
{
foreach ($requests as $index => $request) {
if ($index % 2 === 0) {
$successHandler(new Response(/*...*/), $index);
} else {
$errorHandler(new BadResponseException(/*...*/), $index);
}
}
}
};
$myService = new MyService($client);
$result = $myService->performPoolRequest(/*...*/);
self::assertEquals(/*...*/, $result);
}
Since Guzzle is used as the http client, I decided to use its capabilities in terms of creating stubs for the response object. Here is a link to the documentation Guzzle documentation. The solution turned out to be simple and allowed us to extensively test the business logic of the response.

Symfony passing request to function to an other controller

I try to give '$_REQUEST['vider']' to an other controller like this :
return $this->forward('TestBundle:Rapport:bo', array('vider' => 'vider'));
//, array ($_REQUEST['vider'] => 'vider) doesn't work too
But in my function Rapport:bo, $_REQUEST['vider'] is null, i give it in the array, where i failed ?
edit :
my Rapport:bo function :
public function boAction(Request $request) {
var_dump($_REQUEST['vider']); // is null
if ( isset($_REQUEST['vider']) ) ) {
var_dump('test');
}
}
Try with:
public function boAction($vider) {
your logic...

Symfony2 Service with an unique instance

Please i need some help:
I have the following services:
SERVICE CONFIGURATION IN services.yml
services:
xpad.producto_repository:
class: Xpad\ProductoBundle\Entity\ProductRepository
factory_service: doctrine.orm.clientes_entity_manager
factory_method: getRepository
arguments:
- Xpad\ProductoBundle\Entity\Product
backend_cliente.producto_filters:
class: Xpad\BackendClienteBundle\Filters\ProductFilters
calls:
- [setRepository, ["#xpad.producto_repository="]]
scope: container
AND THE CLASS FOR backend_cliente.producto_filters IS:
namespace Xpad\BackendClienteBundle\Filters;
use Xpad\ProductoBundle\Entity\ProductRepository;
class ProductFilters
{
private $_queryBuilder;
public function getQueryBuilder()
{
return $this->_queryBuilder;
}
public function setQueryBuilder($queryBuilder)
{
$this->_queryBuilder = $queryBuilder;
}
public function setRepository(ProductRepository $productRepository = null)
{
if($this->_queryBuilder == null)
{
$this->_queryBuilder = $productRepository->createQueryBuilder('p');
}
}
}
AND I HAVE THE FOLLOWING ACTION IN ONE OF MY CONTROLLERS:
class ProductController extends Controller
{
............
public function indexAction(Request $request)
{
//SOME CODE
$service_filter = $this->container->get('backend_cliente.producto_filters');
$queryBuilder = $service_filter->getQueryBuilder();
//SOME OTHER CODE
}
MY PROBLEM IS: ANYTIME THAT THE indexAction is execute I GOT A NEW INSTANCE OF backend_cliente.producto_filters SERVICE AND I DON'T KNOW WHY. I NEED AND UNIQUE INSTANCE AS A SINGLETON BECAUSE A HAVE THE $_queryBuilder ATRIBUTTE AND I NEED TO GET THE VALUE OF IT JUST MODIFY ITS VALUE WHEN IS NEEDED;
PLEASE HELP I DON KNOW WHAT I'M DOING WRONG.
Do you have to use the class as a service?
Why don't you use a Singleton, without using a service? Like this:
namespace Xpad\BackendClienteBundle\Filters;
use Xpad\ProductoBundle\Entity\ProductRepository;
class ProductFilters {
private $_queryBuilder;
private static $reference = null;
public function getInstance(){
if (self::$reference === null)
self::$reference = new ProductFilters();
return self::$reference;
}
private function __construct(){}
public function getQueryBuilder()
{
return $this->_queryBuilder;
}
public function setQueryBuilder($queryBuilder)
{
$this->_queryBuilder = $queryBuilder;
}
public function setRepository(ProductRepository $productRepository = null)
{
if($this->_queryBuilder == null)
{
$this->_queryBuilder = $productRepository->createQueryBuilder('p');
}
}
}
And call it with:
...
$filter = ProductFilters::getInstance();
...

How I get the parameter value in my twig extension class of symfony2

I need to get a parameter value in my following twig extension class
namespace xxxx\WebBundle\Twig;
use Symfony\Component\HttpKernel\KernelInterface;
class MyExtension extends \Twig_Extension
{
public function getFilters()
{
return array(
new \Twig_SimpleFilter('affliate', array($this, 'urlFilter')),
);
}
public function urlFilter($url,$aff)
{
$separator = "?";
if (strpos($url,"?")!=false) {
$separator = "&";
}
$parse = parse_url($url);
//echo $parse['host'];
$app_url = $url.$separator.'tag='.$aff;
return $app_url;
}
public function getName()
{
return 'wishbot_extension';
}
}
In controller we can use like this $this->container->getParameter('contact_email');
But I need the value in twig extension class.
Inject the parameters as arguments into your twig extensions's constructor like this:
config.yml
services:
twig.extension.your_extension:
class: Vendor\YourBundle\Twig\Extension\YourExtension
arguments: [ %parameter1%, %parameter2% ]
tags:
- { name: twig.extension }
YourExtension.php
protected $parameter1;
protected $parameter1;
public function __construct($parameter1, $parameter2)
{
$this->parameter1 = $parameter1;
$this->parameter2 = $parameter2;
}
// ....
public function urlFilter($url,$aff)
{
// access the parameters using $this->parameter1
}

Symfony2 + Twig: Translate label into a new twig extension

I have implemented a new twig extension and I have some text which had to be translated.
Unfortunately when I use a code label it appears as a sample text.
I mean when twig render this following extension, it displays: 5 entity.years instead of 5 years for example:
class MyExtension extends \Twig_Extension {
public function getFilters()
{
return array(
'myextension' => new \Twig_Filter_Method($this, 'myextension'),
);
}
public function myextension ($myId)
{
// ....
// Some operations concerning $myId...
// ....
if($myId!=0) {
$res = $myId. ' '.'entity.year';
} else {
$res = ($months == 0 ? $days.'entity.days' : $months.'entity.months');
}
return $res;
}
}
Where entity.years, entity.months, entity.days is defined into my translations folder.
Inject the translator service into your extension and use it. For example:
class MyExtension extends \Twig_Extension
{
private $translator;
public function __construct(Translator $translator)
{
$this->translator = $translator;
}
// ...
public function myMethod()
{
return $this->translator->trans('my_string');
}
}

Resources