How to accept a single, default field in a Symfony form? - symfony

I have a REST API written in Symfony3, with help from the FOSRestBundle.
It makes use of Symfony form classes for data input (POST, PATCH, PUT actions), which works great for almost all endpoints.
However I have a child endpoint that sets up relations using a form with a single collectionType. A POST request body looks like this:
curl http://localhost/documents/100/related -d #- <<REQUEST_BODY
{
"related": [
{"id": 14},
{"id": 23}
]
}
REQUEST_BODY
However I would like to ommit the "related" field name as this information is already in the URI and seems redundant here. I would like to adjust the form to accept data like this:
curl http://localhost/documents/100/related -d #- <<REQUEST_BODY
[
{"id": 14},
{"id": 23}
]
REQUEST_BODY
But cannot see how to make a Symfony form behave in this way?
To clarify, I want to accept a single form field without having to specify the name of that field in a JSON request.

I had a similar problem a while back. What worked for me, was to use the form factory to create a named form with an empty name, like so (example when inside a typical controller):
/** #var $formFactory FormFactory */
$formFactory = $this->get('form.factory');
$form = $formFactory->createNamed('', $type, $data, $options);
Be aware that a form configured like this will consume all POST (or GET) data. So, if you can't ensure that only the required data will be present, you might need to use allow_extra_fields

Related

Symfony 3: headers set in WebTestCase are not present when retrieving request via Request::createFromGlobals()

I'm trying to write a functional test to validate a header sent along with a request. Using Symfony's WebTestCase i have:
$this->client->request(
'POST',
'my-endpoint',
[],
[],
[
'HTTP_My-custom-header' => 'some_value'
],
$this->data);
Within a controller, i can see the headers as expected form the $request argument passed in to an action method.
However, the code i am testing is not a controller, and retrieves the current request (and therefore headers) via Request::createFromGlobals(). From this context, the header is missing.
Why is the header missing?
thanks

Drupal 8, http request to server and append to the site

I have a Drupal 8 site and I need to make a http request to another server (for content) and append it into the page like footer. I can't do this after DOM is loaded because of SEO issues.
I'm familiar with WordPress and so easy to do it with WP. However, I'm confused about how to do this with .twig, Drupal 8. Any suggestions would be great. Thanks.
If you want the content to be part of the DOM when it is sent to the browser this is not something you want to do in Twig, you should have the content loaded earlier in the process.
You can create a module that defines custom block and place that block in the correct region of your theme.
The block plugin class requires you to write a build() method that returns a render array for your block. Within build() you can do whatever you need to acquire the content, including making an HTTP Request using Symfony's Guzzle client:
public function build() {
$url = 'https://www.example.com/remote/service';
$client = \Drupal::httpClient();
$request = $client->createRequest('GET', $url);
// Do whatever's needed to extract the data you need from the request...
$build = ['my_remote_block' => [
'#theme' => 'my_custom_theme_function',
'#attributes' => [
//An array of variables to pass to the theme
],
'#cache' => [
//Some appropriate cache settings
],
],
];
If you are getting HTML back from your request you could skip the custom theme function and return an array with '#type' => 'markup' and then a field for the markup. The rest of this example assumes you get data back and want to render it yourself.
In your module's .module file you can define the custom theme function (so you can use a twig file of your own design).
function my_module_theme($existing, $type, $theme, $path) {
return [
'my_custom_theme_function' => [
'variables'=> [
// defaults for variables used in this block.
],
],
];
}
Then finally you can create a twig file named my-custom-theme-function.html.twig to render the output.
Often these kinds of setups are quite slow (since the browser's request then triggers another HTTP request + processing time) so you should consider either caching the block as much as possible or using a technique like BigPipe (which is probably not an option for you based on your question but seemed worth pointing out).

How to handle submitted array of json with fosrest bundle and nemio api doc bundle

I have a controller in my Rest API that expects an array of json (in POST)
{
data: [
{
name: "marc"
},
{
name: "john"
}
]
}
Submitted data are then saved in database.
I don't know what annotation to use in order to tell "nelmio api doc bundle" to generate the appropriate html page in order to have capability to test my API by creating multiple items (an array of items).
To resume the question is : Can nelmio documentation generates a dynamic collection of forms ?
You can test your API through nelmio sandbox.
Nelmio have the "New Parameter" button which is can add multiple key => value parameters.

Generate Url [symfony 2]

I want to send variables in the url but I don't know How can I send them like this: url/page=1&element=a&...&...&...&..
because when I use the normal symfony url , I don't get the variable in the correct place.
I made it like the default Url of symfony :
pattern: /url/{a}/{b}/{c}/{d}/{e}
but if I send only "e" for example my code take it as "a"
Acces the url with query parameters if you want: /url?page=1&foo=bar. Your routing looks then very simple
my_route:
pattern: /url
default: # bla
in your controller action (you have to take care on validating the values):
use Symfony\Component\HttpFoundation\Request;
public function updateAction(Request $request)
{
$page = $request->query->get('page');
}
If you want a cleaner way, you should take a look at the ParamFetcher of the FOSRestBundle

Content length: 0 in a json response Symfony2

Always i get a blank, i have a action in my controller like this
/**
* #Route("/check/{key}.json", defaults={"_format"="json"})
* #Template()
*/
public function processAction($upload_key)
{
/* make thing */
return array('data' => $process_data);
}
in my process.json.twig file i have
{% set res = { 'data': data } %}
{{ res | json_enconde | raw }}
other form
{{ { 'data': data } | json_enconde | raw }}
i've try this too:
{{ 'hello' | json_encode | raw }}
in chrome i get this response:
Connection:close
Content-Length:0
Content-Type:application/json
Date:Mon, 19 Dec 2011 05:13:17 GMT
Server:Apache/2.2.20 (Ubuntu)
X-Powered-By:PHP/5.3.6-13ubuntu3.3
and get nothing from the server, i cant solve this
There are two ways to achieve this, it depends on which you prefer and whether or not your action is supposed to support multiple _format types.
Option A - An action that only returns JSON
You can bypass the template completely.
In your controller remove the #Template annotation and instead return new Response(json_encode($process_data));
Option B - An action that supports different formats OR you just wish to render the JSON in a template
By an action that renders different formats I refer to an action with a route as so:
#Route("/check/{key}.{_format}", defaults={"_format"="json"}
#Template
Although a controller in this question goes down the route of "an action that only supports JSON but you want to render it in a template".
Assuming the controller's processAction returns return array('data' => $process_data); as the question asks then rendering this as JSON inside a template called process.json.twig should be done as follows {{ data|json_encode }}, there is no need to pre-process data or turn it into another array or anything like that inside the template.

Resources