How to render a controller with get parameters in twig?
{{ render(controller('AutoBundle:MyController:main', { 'id': id, 'active': true } )) }}
to call controller like this: https://example.com/users/323?active=true
In accordion with the doc the query argument is the third parameters.
{{ controller(controller, attributes, query) }}
So try this:
{{ render(controller('AutoBundle:MyController:main', {}, { 'id': id, 'active': true } )) }}
Hope this help
Yes, it doesn't send the parameters as a GET request, but seems to call the method directly.
Twig template part:
<div id="question-choose-semester">
{{ render(controller('UnswCamsBundle:Semester:choiceAjax', { 'redirect': path(app.request.attributes.get('_route'), app.request.attributes.get('_route_params'))} )) }}
</div>
Create an optional parameter. If using annotations to define the route, you don't have to add it to the annotation specification.
public function choiceAjaxAction($redirect = "", Request $request) {
Then check the GET parameter:
if (empty($redirect)) {
$redirect_uri = $request->query->get('Redirect');
} else {
Related
I created a "Ask for support" contact form (using a modal) in my app. What would be the best/cleanest way to add/attach a dump of the $request variable? (PHP's global variables, session data, ...) Because I believe this data can help me a lot to debug.
What I tried:
SupportController:
public function send(Request $request)
{
Mail::send('emails.support', ['request' => $request], function ($message) use ($request) {
$message->from($request->user()->email, $request->user()->name);
$message->subject(trans('Support request'));
});
$request->session()->flash('flash_message', __('Message sent!'));
return redirect()->back();
}
emails.support.blade
{{ print_r($request) }}
But I get a memory size exhausted error message (even after I changed the limit to 1GB).
So there might be a better way to do this. Maybe also a more readable way.
Don't dump the entire request object, instead pick and choose what you find necessary to be helpful for debugging. For example:
All:
#foreach($request->all() as $key => $val)
{{ $key }} = {{ $val }}
#endforeach
<hr>
Route Name: {{ $request->route()->getName() }}
Route Action: {{ $request->route()->getAction() }}
Route Method: {{ $request->route()->getMethod() }}
<hr>
Headers:
#foreach($request->headers->all() as $key => $val)
{{ $key }} = {{ $val }}
#endforeach
Etc, etc..
Or you can use Guzzle's str method to serialize a request or response object.
I have a problem with form.
For start, in my main twig I include the twig i use for the form:
{% include 'MainBundle::manage.html.twig'%}
The controller is mainController
The controller displays everything that appears in main twig.
The action of the form :
public function manageAction(Request $request){
$manageForm = $this->createFormBuilder()
->add('submitFile', FileType::class, array('label' => 'File to Submit'))
->add('send', SubmitType::class)->getForm();
if ($request->getMethod('post') == 'POST') {
// Bind request to the form
$manageForm->bindRequest($request);
// If form is valid
if ($manageForm->isValid()) {
// Get file
$file = $manageForm->get('submitFile');
$file->getData();
}
}
return $this->render('MainBundle::main.html.twig', array(
'manageForm' => $manageForm->createView()
));
}
routing.yml
manage:
path: /manage
defaults:
_controller: MainBundle:Main:manage
requirements:
_method: POST
manage.html.twig
{% extends 'MainBundle::main.html.twig' %}
{% block content %}
<form action="" method="post">
{{ form_widget(manageForm) }}
<input type="submit" />
</form>
{% endblock %}
when i run in the route /main I should have my form display but i have an error
Variable "manageForm" does not exist.
I guess the controller does not take the view...
In your particular case - change to following.
return $this->render('MainBundle::manage.html.twig', array(
'manageForm' => $manageForm->createView()
));
If you extend the main/base twig in other twig, then you need to render this other twig (always).
Parameters which you pass to extended twig will be available in twig you have extended (in this case the main.html.twig), but it doesn't work the other way around.
{% include 'MainBundle::manage.html.twig'%} // why ?
Don't do anything with main - just extend it in manage!!!!
I see other problems with your overall code also.
CONTROLLER:
// the more modern way instead of checking manually for request method
if ($form->isSubmitted()) {
if ($form->isValid()) {
// perform actions...
} else {
// was not valid...return error messages
}
}
FORM
<form action="" method="post"> // this is the oldschool way
{{ form_widget(manageForm) }}
<input type="submit" />
</form>
Better something like... (some of my recent coded examples)
{{ form_start(form, {'attr' : {'method' : 'post', 'enctype' : 'multipart/form-data', 'class' : 'test'}}) }}
{{ form_errors(form.resume) }}
{{ form_widget(form.resume, {'attr' : {'id' : 'file-upload-rec', 'class' : 'file-upload-rec js-file-upload-rec', 'accept' : '.pdf, .doc, .docx'}}) }}
{{ form_label(form.resume, 'select', {'label_attr' : {'class' : 'file-upload js-file-upload'}}) }}
{{ form_row(form._token) }}
{{ form_end(form, {'render_rest': false}) }}
ps. you might also want to read all of https://symfony.com/doc/current/forms.html
You are rendering main.html.twig instead of manage.html.twig. I guess the first one uses an importForm variable which is therefore not passed to the view.
If not, and you really need to render main.html.twig which includes manage.html.twig, then why is manage.html.twig extending main.html.twig? Either include one in another, or extend one from another, not both.
You need to pass the variable while including your template
{% include 'MainBundle::manage.html.twig' with {'manageForm': manageForm} %}
For more information see https://twig.symfony.com/doc/2.x/tags/include.html
Thanks!
I have an issue trying to render a controller which returns a template with formView.
I understood about the sub-request, but I am having difficult time to show any kind of errors.
I think the problem is that after it sees the form is invalid it redirectsToRoute and it looses the POST Request.
If I don't say redirectTo it just renders the view.
base.html.twig
{{ render(controller('AppBundle:Utility:renderSignUpWizard'), {request: app.request}) }}
Utility Controller
/**
* #Route("/registration/wizard/", name="registration.wizard")
*/
public function renderSignUpWizardAction(Request $request)
{
/** #var $user User */
$user = $this->getUser();
$form = $this->createForm(SignUpWizardType::class, $user);
$form->handleRequest($request);
if ($form->isSubmitted() && $form->isValid())
{
// save changes to user
$this->persistAndSave($user);
// redirect to profile
return $this->redirectToRoute('profile');
}
else if($form->isSubmitted() && !$form->isValid())
{
return $this->redirectToRoute('home');
}
return $this->render('partials/signup-wizard.html.twig', array
(
'form' => $form->createView(),
));
}
If you could show the twig file where you put the form I could have given a clearer answer. Check the twig file you tell your controller to render and add the following:
Simple way to generate your form(doesn't include errors):
{{ form_start(form) }}
{{ form_widget(form) }
{{ form_end(form) }}
Add:
{{ form_errors(form) }}
if you want erors for a specific field:
{{ form_errors(form.name) }}
In Twig partial rendered by separate controller, I want to check if current main route equals to compared route, so I can mark list item as active.
How can I do that? Trying to get current route in BarController like:
$route = $request->get('_route');
returns null.
Uri is also not what I'm looking for, as calling below code in bar's twig:
app.request.uri
returns route similar to: localhost/_fragment?path=path_to_bar_route
Full example
Main Controller:
FooController extends Controller{
public function fooAction(){}
}
fooAction twig:
...some stuff...
{{ render(controller('FooBundle:Bar:bar')) }}
...some stuff...
Bar controller:
BarController extends Controller{
public function barAction(){}
}
barAction twig:
<ul>
<li class="{{ (item1route == currentroute) ? 'active' : ''}}">
Item 1
</li>
<li class="{{ (item2route == currentroute) ? 'active' : ''}}">
Item 2
</li>
<li class="{{ (item3route == currentroute) ? 'active' : ''}}">
Item 3
</li>
</ul>
pabgaran's solution should work. However, the original problem occurs probably because of the request_stack.
http://symfony.com/blog/new-in-symfony-2-4-the-request-stack
Since you are in a subrequest, you should be able to get top-level (master) Request and get _route. Something like this:
public function barAction(Request $request) {
$stack = $this->get('request_stack');
$masterRequest = $stack->getMasterRequest();
$currentRoute = $masterRequest->get('_route');
...
return $this->render('Template', array('current_route' => $currentRoute );
}
Haven't run this but it should work...
I think that the best solution in your case is past the current main route in the render:
{{ render(controller('FooBundle:Bar:bar', {'current_route' : app.request.uri})) }}
Next, return it in the response:
public function barAction(Request $request) {
...
return $this->render('Template', array('current_route' => $request->query->get('current_route'));
}
And in your template compares with the received value.
Otherwise, maybe is better to use a include instead a render, if you don't need extra logic for the partial.
in twig you can send request object from main controller to sub-controller as parameter:
{{ render(controller('FooBundle:Bar:bar', {'request' : app.request})) }}
in sub-controller:
BarController extends Controller{
public function barAction(Request $request){
// here you can use request object as regular
$country = $request->attributes->get('route_country');
}
}
I have a search function on my website implemented with elasticsearch.
Now I have a little question about design.
I have a searchAction with route /search that takes a parameter in the query string. Like /search?terms=....
I would like to make the results list filterable, but I have some doubts about the right design to achieve this.
What is the best solution to make a list of filtered results?
If I pass the filter parameter I need to specify a form action with the current url and append the current query string like a link, right?
Example:
<form action="{{ current_pat }} ~ {{ query_string }}" method="post">
<input type="checkbox" name="filter_one">....
In this case the url will like: /search?terms=... and in $post I have the filter. Is this the right solution, or is a list of links better?
Example:
<ul>
<li><a href="{{current_path}} ~ {{ query_string }} ~ {{ this_filter }}">...
<li><a href="{{current_path}} ~ {{ query_string }} ~ {{ this_another_filter }}">
...
In this case the url will be like: /search?terms=...&this_filter=...
In the form case with the get parameter and post filter I need to take both type of parameters in the search action. Is this good?
Instead the link will now have all parameters in the $get request, but I don't like to build the url with query strings in the template.
What's the best way?
Use KNP paginator bundle with search action. On search form make the post action to your searchAction in Controller and after sorting data with matching criteria, re-render the page.
public function searchAction(Request $request,array $arguments = array())
{
$em = $this->getDoctrine()->getManager();
$paginator = $this->get('knp_paginator');
$parameter = $request->get('board_search');
$boardRepo = $this->getDoctrine()->getRepository('PNCMISDashboardBundle:ExaminationBoards')->loadBoardByName($parameter);
$boards = $paginator->paginate($boardRepo, $this->get('request')->query->get('page', 1), 10);
return $this->render('PNCMISDashboardBundle:ExaminationBoards/CRUD:index.html.twig', array(
'boards'=> $boards,
)
);
}
public function loadBoardByName($name)
{
$q = $this
->createQueryBuilder('boards')
->where('upper(boards.name) LIKE upper(:search)')
->setParameter('search', '%'.$name.'%')
->getQuery()
;
try {
// The Query::getSingleResult() method throws an exception
// if there is no record matching the criteria.
$user = $q->getResult();
} catch (NoResultException $e) {
throw new UsernameNotFoundException(sprintf('Unable to find an board identified by "%s".', $name), null, 0, $e);
}
return $user;
}
I prefer to have all the parameters in the query string which will allow the user to bookmark the url or send it in an email.
It depends.
1 If you don't need to index (SEO for instance - google bot) the filtered results page, in my opinion you should use AJAX to achieve this.
Routing:
search_result:
pattern: /search
defaults: { _controller: AcmeExampleBundle:Ajax:searchResult }
requirements:
_method: POST
JavaScript (pseudo Code)
filterResults() {
var queryString = $('input#toSearch').val();
var filters = new Object();
filters['someKey'] = someVal;
$.post('/search', {filters: filters, queryString: queryString}, function(data) {
$('#resultList').html(data);
});)
}
Of course, you should not harcode url '/search'.
Controller:
// src/Acme/ExampleBundle/Controller/AjaxController.php
// ...
public function searchResultAction()
{
$filters = $this->getRequest()->get('filters', array());
$searchObject = new searchObj();
// or smt like $this->get('service_name'); if you use search object as service
// you can also use entity manager
$searchObject->setQueryString($this->getRequest()->get('queryString'));
$searchObject->setFilters($filters);
return $this->render('AcmeExampleBundle:Ajax:searchResult.html.twig', array(
'records' => $searchObject->getResults()
));
}
Of course you can return json response, but in my opinion, return ready to inject part of template is simplest to manage
And View:
{% for record in records %}
<div class="record">{{ record.title }}</div>
{% endfor %}
2 If you wanna index filtred results page you should use user-friendly URLs instead AJAX methods
Routing:
search_result:
pattern: /search/{queryString}/{make}/{model}
defaults: { _controller: AcmeExampleBundle:Ajax:searchResult }
requirements:
_method: GET
Controller:
// src/Acme/ExampleBundle/Controller/AjaxController.php
// ...
public function searchResultAction($queryString, $make, $model)
{
$filters = array('make' => $make, 'model' => $model);
$searchObject = new searchObj();
// or smt like $this->get('service_name'); if you use search object as service
// you can also use entity manager
$searchObject->setQueryString($queryString);
$searchObject->setFilters($filters);
return $this->render('AcmeExampleBundle:Ajax:searchResult.html.twig', array(
'records' => $searchObject->getResults()
));
}