Symfony2 get request in action called in twig - symfony

I have a twig template with :
{% render controller('MyBundle:Default:leftside') %}
So i have an action leftside in my controller :
public function leftsideAction(Request $request)
I'm trying, in this action to retrieve GET parameters with :
$request->get('MY_PARAM')
But it's always empty, i think, because i render this action in my template, i can't retrieve all my request.
How can i do that ?

That's totally expected due the concept of request stacks.
The Request supplied to "main" action is, well, MASTER_REQUEST, while those supplied via render controller tag are SUBREQUEST.
You can read more about RequestStack feature here.
Now, in order to have access parameters defined in MASTER_REQUEST you need to get request_stack service and then get the master request. After that, it's business as usual:
public function leftsideAction(Request $request){
$stack = $this->get('request_stack');
$master = $stack->getMasterRequest();
$master->get('MY_PARAM'); // This should work
$request->get('MY_PARAM'); // But this should not
}
Here is the definition of RequestStack class: link

Related

How to programatically change the routing to add my own "filter" by keyword

My case is the following:
I have a Shopware Bundle and i need to change/extend the routing in such a way that if a request URL contains a keyword "xyz", the request is forwarded to a controller in my bundle without checking further if the route is available in "static routes" for example.
For instance: "/xyz/1/lorem/3" or "/xyz/5/3/ipsum" etc. all need to be rerouted to the controller in my bundle, since they contain the keyword /xyz.
Is there a service i can overwrite/decorate or something similar where i can implement this behaviour?
You can have a placeholder in your route with a default and a requirement allowing for all characters:
/**
* #Route("/xyz{anything}", name="frontend.my.action", methods={"GET"}, defaults={"anything"=""}, requirements={"anything"=".+"})
*/
public function myAction(Request $request): Response
{
$anything = $request->get('anything');
// ...
}
This will match any url starting with /xyz and every set of characters that follows afterwards is considered to be part of anything.

Symfony : Route PUT method

Anyone knows why the PUT method doesn't work using PHP Symfony?
If I replace PUT to POST everything works fine
/**
* #Route("/api/product/update", name="product_udpate", methods = {"PUT"})
*/
i am reading variables like that
$request = Request::createFromGlobals();
echo $request->request->get('name');
error:
No route found for "PUT /api/product/update/23" (404 Not Found)
The problem is you are not creating the route correctly. Basically, you need to add the "id" to the route.
/**
* #Route("/api/product/update/{id}", name="product_udpate", methods = {"PUT"})
*/
public function updateAction(Request $request, $id)
{
// Your logic here
$name = $request->get('name');
}
You got the following error because you have not configured route correctly.
error: No route found for "PUT /api/product/update/23" (404 Not Found)
If you want to add id along with your desire url, you have to define in your route.
Thus, you can update your route:
/**
* #Route("/api/product/update/{id}", name="product_udpate", methods = {"PUT"}, defaults={"id"=null})
*/
As stated in the symfony documentation How to Use HTTP Methods beyond GET and POST in Routes
Unfortunately, life isn't quite this simple, since most browsers do not support sending PUT and DELETE requests via the method attribute in an HTML form. Fortunately, Symfony provides you with a simple way of working around this limitation. By including a _method parameter in the query string or parameters of an HTTP request, Symfony will use this as the method when matching routes
So you have to fake the method like this one :
<form action='your route'>
<input type='hidden' name='_method' value='PUT'>
//do something.......
</form>

SilverStripe 4 : FunctionalTest "get" method returns 404 status although the page is there.

I am trying to test a controller with this Test class,
<?php
use SilverStripe\Dev\FunctionalTest;
class SitePageControllerTest extends FunctionalTest
{
protected static $fixture_file = 'site/tests/fixturesSitePage.yml';
public function testViewSitePage()
{
$obj = $this->objFromFixture('SitePage', 'page1');
$page = $this->get('page-one/');
$this->assertEquals(200, $page->getStatusCode());
}
}
and Fixture.
SitePage:
page1:
Title: Page One
CanViewType: true
But "$this->get('page-one/');" returns a 404 page.
Pages are versioned, and this one isn't published at the point where you ask for it, so the functional test emulates a frontend web request which is served from the live (published) stage by default.
You can use the draft site by appending ?stage=Stage to your request URL, or by using protected static $use_draft_site = true in your functional test (this is deprecated in 4.2).
Note that FunctionalTest doesn't log a user in, so you may also need to log in with some level of permission i.e. $this->logInWithPermission('ADMIN')
Another option is to publish it using something like: $obj->publishRecursive(); before the get()

How is the callback from a resource owner processed in HWIOAuthBundle?

I am trying to understand how HWIOauthBUndle works. I can see how the initial authorization request to a resource owner is built and made.
I do not see however, how a callback made from a resource owner triggers any controller/action in my application (which it most obviously does, though).
When following the generally available instructions, the callback will be made to something like <path to my app>/check-[resourceOwner], e.g. http://www.example.com/oauth/check-facebook.
In my routing.yml file, I put
facebook_login:
pattern: /oauth/check-facebook
I don't see how any controller is associated with that route, so what actually happens when a callback is made to my application?
The authentication provider system is one of the more complicated features. You will probably want to read through here: http://symfony.com/doc/current/cookbook/security/custom_authentication_provider.html
Callbacks are handled through a request listener. Specifically:
namespace HWI\Bundle\OAuthBundle\Security\Http\Firewall\OAuthListener;
use Symfony\Component\Security\Http\Firewall\AbstractAuthenticationListener;
class OAuthListener extends AbstractAuthenticationListener
{
public function requiresAuthentication(Request $request)
{
// Check if the route matches one of the check paths
foreach ($this->checkPaths as $checkPath) {
if ($this->httpUtils->checkRequestPath($request, $checkPath)) {
return true;
}
}
return false;
}
protected function attemptAuthentication(Request $request)
{
// Lots of good stuff here
How checkPaths get's initialized and how all the calls are made would require a very long explanation. But the authentication provider chapter will get you going.

Symfony2 Templating without request

I'm trying to send an email from a ContainerAwareCommand in Symfony2. But I get this exception when the email template is render by:
$body = $this->templating->render($template, $data);
Exception:
("You cannot create a service ("templating.helper.assets") of an inactive scope ("request").")
I found in github that this helper need the request object. Anybody knows how can I to instance the Request object?
You need to set the container into the right scope and give it a (fake) request. In most cases this will be enough:
//before you render template add bellow code
$this->getContainer()->enterScope('request');
$this->getContainer()->set('request', new Request(), 'request');
The full story is here. If you want to know the details read this issue on github.
The problem arises because you use asset() function in your template.
By default, asset() relies on Request service to generate urls to your assets (it needs to know what is the base path to you web site or what is the domain name if you use absolute asset urls, for example).
But when you run your application from command line there is no Request.
One way to fix this it to explicitely define base urls to your assets in config.yml like this:
framework:
templating:
assets_base_urls: { http: ["http://yoursite.com"], ssl: ["http://yoursite.com"] }
It is important to define both http and ssl, because if you omit one of them asset() will still depend on Request service.
The (possible) downside is that all urls to assets will now be absolute.
Since you don't have a request, you need to call the templating service directly like this:
$this->container->get('templating')->render($template, $data);
Following BetaRide's answer put me on the right track but that wasn't sufficient. Then it was complaining: "Unable to generate a URL for the named route "" as such route does not exist."
To create a valid request I've modified it to request the root of the project like so:
$request = new Request();
$request->create('/');
$this->container->enterScope('request');
$this->container->set('request', $request, 'request');
You might need to call a different route (secured root?), root worked for me just fine.
Symfony2 Docs
Bonus addition:
I had to do so much templating/routing in cli through Symfony2 commands that I've updated the initializeContainer() method in AppKernel. It creates a route to the root of the site, sets the router context and fakes a user login:
protected function initializeContainer()
{
parent::initializeContainer();
if (PHP_SAPI == 'cli') {
$container = $this->getContainer();
/**
* Fake request to home page for cli router.
* Need to set router base url to request uri because when request object
* is created it perceives the "/portal" part as path info only, not base
* url and thus router will not include it in the generated url's.
*/
$request = Request::create($container->getParameter('domain'));
$container->enterScope('request');
$container->set('request', $request, 'request');
$context = new RequestContext();
$context->fromRequest($request);
$container->get('router')->setContext($context);
$container->get('router')->getContext()->setBaseUrl($request->getRequestUri());
/**
* Fake admin user login for cli. Try database read,
* gracefully print error message if failed and continue.
* Continue mainly for doctrine:fixture:load when db still empty.
*/
try {
$user = $container->get('fos_user.user_manager')->findUserByUsername('admin');
if ($user !== null) {
$token = $token = new UsernamePasswordToken($user, null, 'main', $user->getRoles());
$this->getContainer()->get('security.token_storage')->setToken($token);
}
} catch (\Exception $e) {
echo "Fake Admin user login failed.\n";
}
}
}
You might not need the last $container->get('router')->getContext()->setBaseUrl($request->getRequestUri()); part, but I had to do it because my site root was at domain.com/siteroot/ and the router was stripping /siteroot/ away for url generation.

Resources