"Variable "form" does not exist." Symfony - php

Trying to make a simple form but i keep getting "Variable "subscriptionForm" does not exist."
enter image description here
Here is Controller method:
public function subscriptionForm(Request $request): \Symfony\Component\HttpFoundation\RedirectResponse|array
{
$subscriptionForm = $this
->getFactory()
->createSubscriptionForm()
->handleRequest($request);
if ($subscriptionForm->isSubmitted() && $subscriptionForm->isValid()) {
// Call the client for e.g. to save the subscriber.
// Redirect to home page after successful subscription
return $this->redirectResponseInternal('home');
}
return $this->viewResponse([
'subscriptionForm' => $subscriptionForm->createView(),
]);
}
Twig file:
{% block body %}
{{ form_start(subscriptionForm) }}
{{ form_widget(subscriptionForm.email) }}
{{ form_errors(subscriptionForm.email) }}
<input type="submit" value="Subscribe" />
{{ form_end(subscriptionForm) }}
{% endblock %}

Spryker assigns all twig variables within a _view object. Try adding these code on top of the twig file:
{% define data = {
subscriptionForm: _view.subscriptionForm
} %}

Related

Adding a global action in EasyAdmin, place my button underneath the table instead of above

I created a global Action :
public function export(
Admin $user,
StructureRepository $structureRepository,
ExportCsvEntity $exportCsvEntity,
string $entityClass
): HttpFoundationResponse {
$zipcodes = $structureRepository->getZipcodesByStructureFromAdmin($user->getId());
$exportCsvEntity->export(
$zipcodes,
$entityClass
);
return $exportCsvEntity->download($entityClass);
}
public function exportButton(): Action
{
return Action::new('export', 'admin.crud.user.field.activities_tracking.button.export')
->linkToCrudAction('export')
->displayAsLink()
->setCssClass('btn btn-primary')
->createAsGlobalAction()
;
}
Then in my Crud Controller I call it :
if ($this->getUser() instanceof Admin) {
$export = $this->exportAction->exportButton();
$actions->add(Crud::PAGE_INDEX, $export);
}
In the doc its written => Global actions are displayed above the listed entries.
But in my case the button is underneath the table
Have a look here
My template is extending '#!EasyAdmin/crud/index.html.twig'then I override the global_actions block :
{% block global_actions %}
{{ parent() }}
{% endblock global_actions %}
Now my button is above the table but also underneath :
Have a look here
What do I do wrong ?
You are correct when trying to do this by overriding the index template.
An easy way to do this considering how the template is organized is to modify the global_actions block by filtering actions you do not want to show above the list. For example by using a css class to not show a global action above the list.
{% block global_actions %}
<div class="global-actions">
{% for action in global_actions|filter(a => 'under-list' not in a.cssClass) %}
{{ include(action.templatePath, { action: action }, with_context = false) }}
{% endfor %}
</div>
{% endblock global_actions %}
And in your crud controller:
Action::new('customAction', $label, $icon)
->addCssClass('under-list')
->createAsGlobalAction()
->linkToCrudAction('customAction');
And you need to add your new list of actions under your list by overriding the main block.
{% block main %}
{{ parent() }}
{% block under_list_global_actions %}
<div class="under-list-global-actions">
{% for action in global_actions|filter(a => 'under-list' in a.cssClass) %}
{{ include(action.templatePath, { action: action }, with_context = false) }}
{% endfor %}
</div>
{% endblock under_list_global_actions %}
{% endblock main %}
And you should get your custom global action (with the css class under-list) under your list.

Use Variables from Extended Template

I have a question about how to use all variables from extended template.
I have these following PHP Functions as example:
function parent()
{
$total_studies = Studies::where('studies', $studies)->count();
echo $this->twig->render('/studies/parent.html.twig',
[
'number_studies' => $total_studies
]);
}
function child()
{
$study_detail = Studies::where('studies', $studies)->first();
echo $this->twig->render('/studies/child.html.twig',
[
'study' => $studies_detail
]);
}
in my parent.html.twig template, I have define
<h4> {{ number_studies }} </h4>
</ another html codes />
in my child child.html.twig template, I have used
{% use '/studies/parent.html.twig' %}
{% block study_header %} {{ parent() }} {% endblock %}
<h4> {{ study.title }} </h4>
<h5> {{study.cover }} </h4>
and so on..
Now the question is how my child.html.twig can also automatically displaying number of studies that is coming from parent.html.twig ?
Maybe it because the {{ number_studies }} is defined inside function parent() and being rendered there ?
note: I know what AddGlobal is, but I do really want to render the variable and the twig html alone, and then inherit it into whatever that uses /studies/parent.html.twig'

How can I detect if a form has any elements left to be rendered?

Let's say I am using the Symfony Form Component to render a simple form with only two fields (username and email)
I am rendering both fields with form_row() to add custom css around, then call form_widget() to render the rest of the elements (another option would be form_rest())
What I am looking for is a way to check beforehand whether form_widget() will print any objects or not, in order to add custom html in case there are extra fields.
The way I did it is like this:
//app/form/index.html.twig
{# Other template code #}
...
{# Rendering form: #}
{{ form_start(form) }}
{{ form_row(form.username) }}
{{ form_row(form.email) }}
{% set form_rendered = form_widget(form) %}
{% if form_rendered %}
<h3>Other fields</h3>
{{ form_rendered | raw }}
{% endif %}
{{ form_end(form) }}
{# End form #}
...
{# Other template code #}
However, I am not satisfied with it. Is there any better way?
Edit: When using CSRF Protection (activated by default), the previous code would ALWAYS print <h3>Other fields</h3>, since the form has an extra hidden field for the token that we didn't print. We would need to render it somewhere with {{ form_row(form._token) }}.
By checking the code in src/Symfony/Component/Form/FormView.php, I found a function that does exactly what I wanted.
//src/Symfony/Component/Form/FormView.php
/**
* Returns whether the view was already rendered.
*
* #return bool Whether this view's widget is rendered
*/
public function isRendered()
{
$hasChildren = 0 < count($this->children);
if (true === $this->rendered || !$hasChildren) {
return $this->rendered;
}
if ($hasChildren) {
foreach ($this->children as $child) {
if (!$child->isRendered()) {
return false;
}
}
return $this->rendered = true;
}
return false;
}
Now the function can be used in the template as such:
{% if not form.isRendered() %}
<h3>Other fields</h3>
{{ form_widget(form) }}
{% endif %}

Custom validator accessed twice

I have a custom validator on my Symfony2 project.
The validation works fine, but the method is somehow accessed twice.
Here is my custom validator: My other resolved question
The problem is the next:
As you can see, the error message is displayed twice. When I am trying to var dump something in the validate method, the vardump is also displayed twice. Any idea why the validate is called twice? This is called when I am using $form->bind($request); in my controller.
EDIT
Here is the twig template:
{% extends 'MerrinMainBundle::layout.html.twig' %}
{% block page_title %}
MDPI Conversion system (Merrin) 3.0 - New Conversion
{% endblock %}
{% block main %}
{% for flashMessage in app.session.flashbag.get('user-notice') %}
<div class="flash-notice">
{% autoescape false %}
{{ flashMessage }}
{% endautoescape %}
</div>
{% endfor %}
<h1>Create New Manuscript</h1>
{% if valid == false %}
<div class="error">
{{ form_errors(form) }}
{{ form_errors(form.doi) }}
{{ form_errors(form.publisher) }}
{{ form_errors(form.file) }}
</div>
{% endif %}
<form action="{{ path }}" method="POST" {{ form_enctype(form) }}>
</form>
{% endblock %}
And the controller call
public function createAction()
{
$em_scipub = $this->getDoctrine()->getManager();
$em_mdpipub = $this->getDoctrine()->getManager('mdpipub');
$enquiry = new Manuscript();
$formType = new NewManuscriptType();
$form = $this->createForm($formType, $enquiry);
$request = $this->getRequest();
$valid = true;
$error = '';
if ($request->isMethod('POST')) {
$form->bind($request);
if ($form->isValid()) {
... do something ...
$em_scipub->persist($enquiry);
$em_scipub->flush();
$flash_message = "<a href='edit/".$enquiry->getId()."'>New Manuscript</a> sucessfully created.";
$this->get('session')->getFlashBag()->set('user-notice', $flash_message);
return $this->redirect($this->generateUrl('MerrinMainBundle_new'));
}
else
$valid = false;
}
$path = $this->generateUrl('MerrinMainBundle_new');
return $this->render('MerrinMainBundle:Pages:new_conversion.html.twig.twig', array(
'valid' => $valid,
'path' => $path,
'form' => $form->createView(),
) );
}
EDIT2:
The validate function:
public function validate($value, Constraint $constraint)
{
$doi = $value->getDoi();
preg_match('/[^\/]+/i', $doi, $publisherDoiAbbr);
if($publisherDoiAbbr[0] !== $value->getPublisher()->getDoiAbbreviation()) {
$this->context->addViolation($constraint->message_publisher_DOI);
}
else {
preg_match("/[a-z]+/",$doi, $journalDoiAbbr);
$em_mdpipub = $this->entityManager;
$journal = $em_mdpipub->getRepository('MerrinMdpiPubBundle:Journal')->findOneBy(array('doi_abbreviation' => $journalDoiAbbr));
if($journal == null) {
$this->context->addViolation($constraint->message_journal_DOI);
}
}
preg_match('/\d*$/i', $doi, $doiNumericPart);
if(strlen($doiNumericPart[0]) < 8) {
$this->context->addViolation($constraint->message_volume_issue_firstpage_DOI);
}
}
And the twig template:
{% extends 'MerrinMainBundle::layout.html.twig' %}
{% block page_title %}
MDPI Conversion system (Merrin) 3.0 - New Conversion
{% endblock %}
{% block main %}
{% for flashMessage in app.session.flashbag.get('user-notice') %}
<div class="flash-notice">
{% autoescape false %}
{{ flashMessage }}
{% endautoescape %}
</div>
{% endfor %}
<h1>Create New Manuscript</h1>
{% if valid == false %}
<div class="error">
{{ form_errors(form) }}
{{ form_errors(form.doi) }}
{{ form_errors(form.publisher) }}
{{ form_errors(form.file) }}
</div>
{% endif %}
<form action="{{ path }}" method="POST" {{ form_enctype(form) }}>
<div style="float:left;">
<table width="700">
<tr>
<td>
{{ form_label(form.doi) }}
</td>
<td>
{{ form_widget(form.doi, { 'attr': {'size': 40} }) }}
</td>
</tr>
<tr>
<td>
{{ form_label(form.publisher) }}
</td>
<td>
{{ form_widget(form.publisher) }}
</td>
</tr>
<tr>
<td>
{{ form_label(form.file) }}
</td>
<td>
{{ form_widget(form.file) }}
</td>
</tr>
<tr>
<td>
</td>
<td>
<input class="submit-confirm-button" type="submit" name="update-text" value="submit" />
<a class="cancel-link" href="{{ path('MerrinMainBundle_homepage' ) }}">Cancel</a>
</td>
</tr>
</table>
</div>
{{ form_rest(form) }}
</form>
{% endblock %}
EDIT 3:
Here is how I am applying the validator to the entity:
/**
* Manuscript
*
* #IsDOI()
* #ORM\Table(name="manuscripts")
* #ORM\Entity(repositoryClass="Merrin\MainBundle\Repository\ManuscriptRepository")
* #ORM\HasLifecycleCallbacks
*
*/
class Manuscript
{
....
}
EDIT 4:
When I try to vardump the
$form->getErrors();
I am getting an array with two values:
array(2) {
[0]=>
object(Symfony\Component\Form\FormError)#507 (4) {
["message":"Symfony\Component\Form\FormError":private]=>
string(77) "The Publisher DOI abbreviation does not correspond to the DOI you filled in !"
["messageTemplate":protected]=>
string(77) "The Publisher DOI abbreviation does not correspond to the DOI you filled in !"
["messageParameters":protected]=>
array(0) {
}
["messagePluralization":protected]=>
NULL
}
[1]=>
object(Symfony\Component\Form\FormError)#542 (4) {
["message":"Symfony\Component\Form\FormError":private]=>
string(77) "The Publisher DOI abbreviation does not correspond to the DOI you filled in !"
["messageTemplate":protected]=>
string(77) "The Publisher DOI abbreviation does not correspond to the DOI you filled in !"
["messageParameters":protected]=>
array(0) {
}
["messagePluralization":protected]=>
NULL
}
}
This is possible if you are using validation groups and apply validator to several groups. And what #IsDOI() annotation mean? If its apply validation possible that you first add validator in validation.yml and second via this custom annotation.
The problem is that you're rendering it twice.
Here:
{{ form_errors(form) }}
followed by:
{{ form_errors(form.doi) }}
{{ form_errors(form.publisher) }}
{{ form_errors(form.file) }}
Since you are displaying the errors in single place, I recommend using only the first method.
As stated in the form_errors twig reference:
form_errors(view)
Renders any errors for the given field.
{{ form_errors(form.name) }}
{# render any "global" errors #}
{{ form_errors(form) }}
Since you have a lot of custom code (EntityManager, Validator) it is hard to tell the error with the amount of code you provide because it's not possible to recreate the error locally.
But here are my suggestions:
In your Validator there are two possible cases the following violation gets thrown
$this->context->addViolation($constraint->message_publisher_DOI);
On both occasions the error message is the same. Maybe both of these cases apply. Try to debug this by adding an individual error message for both cases.
I don't know the code of your Form-Class but maybe you apply your custom validator to multiple fields? Also remove validations for each field individually to see where the duplicate error message is thrown.
One last mistake I can imagine would be a custom Form-Template. If you have one check whether or not you maybe call the {{ form_error(form) }} block or any other block multiple times.
I hope one of my suggestions did help you.

Advanced routing parameter handling in twig and Symfony2

I have this configuration:
A page containing a search field, at the submit in the same page I want a list of every result matching the research, everyone linking to a corresponding route. For example if I find 4 elements, I want that in the resulting page 4 links Azienda1, Azienda2 ecc.
Now I get this error:
An exception has been thrown during the rendering of a template ("The "ABCAziendaBundle_visualizza_azienda" route has some missing mandatory parameters ("id_azienda").") in ::base.html.twig at line 27.
500 Internal Server Error - Twig_Error_Runtime
1 linked Exception:
MissingMandatoryParametersException
Here are the key files,
#config.yml
ABCAziendaBundle_visualizza_azienda:
pattern: /visualizza_azienda/{id_azienda}
defaults: { _controller: ABCAziendaBundle:Default:showAzienda }
requirements:
id_azienda: \d+
ABCAziendaBundle_azienda_index:
pattern: /
defaults: { _controller: ABCAICAziendaBundle:Default:indexAzienda }
#DefaultController.php
public function indexAziendaAction(Request $request) {
$searchFormType = new SearchAziendaType();
$form = $this->createForm($searchFormType);
if ($request->getMethod() == 'POST')
{
$form->bindRequest($request);
if ($form->isValid())
{
$data = $form->getData();
$em = $this->getDoctrine()->getEntityManager();
$aziende = $em->getRepository('ABCAziendaBundle:Azienda')->findAziendaByAliasOrRagioneSocialeSubstring($data["search_field"]);
return $this->render('ABCAziendaBundle:Default:indexAzienda.html.twig', array('form' => $form->createView(), 'aziende' => $aziende));
}
}
return $this->render('ABCAziendaBundle:Default:indexAzienda.html.twig', array('form' => $form->createView()));
}
public function showAziendaAction($id_azienda) {
echo "non entra qui";
}
#indexAzienda.html.twig
{% extends "::base.html.twig" %}
{% block pagetitle %}ABC{% endblock %}
{% block body %}
<h2>Ricerca azienda</h2>
<div id="form_container">
<form action="{{ path('ABCAziendaBundle_azienda_index') }}" method="post" {{ form_enctype(form) }}>
{{ form_label(form.search_field, "Ricerca Azienda") }}
{{ form_widget(form.search_field) }}
<input type="submit" />
</form>
<button>nuova azienda</button>
</div>
{% if aziende is defined %}
{% for azienda in aziende %}
<div class="areaTot">
{{azienda.alias}}
</div>
{% endfor %}
{% else %}
<div class="areaTot">
<p>"NIENTE"</p>
</div>
{% endif %}
{% endblock %}
I think its a typo on your side:
<a href="{{ path('ABCAziendaBundle_visualizza_azienda', { 'azienda_id' : azienda.id }) }}">
Should be:
<a href="{{ path('ABCAziendaBundle_visualizza_azienda', { 'id_azienda' : azienda.id }) }}">
The difference is the route parameter, you wrote azienda_id initialy, but the route parameter name is id_azienda
Should clear the error.
Regards,
Matt

Categories