I am new to Symfony2 and I am just trying some stuff to learn Symfony2.
Currently, I have a few controllers which can perfrom some simple tasks. A simple crud controller for example.
Al my pages extend a base.html.twig file and insert their block into it. Now I want to add a login part to my base file, because I want to be able to login at every page. I was thinking to use the formbuilder for this, but this is php code which can not be in a html.twig file. I have absolutly no idea how to handle this. Can someone push me in the right direction of give my some working example?
Thanking in advance
Actions:
public function loginFormAction(Request $request){
// create a task and give it some dummy data for this example
$message = "";
$account = new Account();
$account->setEmail('login#login.nl');
$form = $this->createFormBuilder($account)
->add('email', 'text')
->add('wachtwoord', 'text')
->add('login', 'submit')
->getForm();
$form->handleRequest($request);
if ($_POST != null && $_POST['form']['email'] != null) {
$repository = $this->getDoctrine()->getRepository('AcmeBlogBundle:Account');
$email =$_POST['form']['email'];
$wachtwoord =$_POST['form']['wachtwoord'];
$foundAccount = $repository->findOneByemail($email);
if (!$foundAccount) {
$message = "Ingevuld email en wachtwoord komen niet overeen.";
}else if($foundAccount->getWachtwoord() == $wachtwoord){
$session = $request->getSession();
$session->set('name', $foundAccount->getVoornaam() . " " . $foundAccount->getAchternaam());
$session->set('email', $foundAccount->getEmail());
//return $this->redirect($this->generateUrl('melding', array('melding' => 'mooiman')));
//return $this->render('AcmeBlogBundle:Account:melding.html.twig', array('melding' => 'Hallo, '.$foundAccount->getVoornaam() . " " . $foundAccount->getAchternaam()));
$message = 'Hallo, '.$foundAccount->getVoornaam() . " " . $foundAccount->getAchternaam();
$form = $this->createFormBuilder()
->add('logout', 'submit')
->getForm();
return $this->render('AcmeBlogBundle:Account:login.html.twig', array('form'=> $form->createView(), 'message' => $message));
}else{
$message = "Ingevuld email en wachtwoord komen niet overeen.";
}
}
return $this->render('AcmeBlogBundle:Account:login.html.twig', array('form'=> $form->createView(), 'message' => $message));
}
public function logoutFormAction(Request $request){
// create a task and give it some dummy data for this example
$session = $request->getSession();
$message = 'Hallo, '.$session->get('name');
$form = $this->createFormBuilder()
->add('logout', 'submit')
->getForm();
$form->handleRequest($request);
if ($_POST != null) {
$account = new Account();
$account->setEmail('login#login.nl');
$form = $this->createFormBuilder($account)
->add('email', 'text')
->add('wachtwoord', 'text')
->add('login', 'submit')
->getForm();
$session->set('name', null);
$session->set('email', null);
$message = "U bent nu uitgelogd";
}
return $this->render('AcmeBlogBundle:Account:login.html.twig', array('form'=> $form->createView(), 'message' => $message));
}
Base.html.twig:
{% if(app.session.get('name') == null) %}
{{ render(controller('AcmeBlogBundle:Account:loginForm')) }}
{% else %}
{{ render(controller('AcmeBlogBundle:Account:logoutForm')) }}
{% endif %}
You can include whole output of other controller/action in template. Just include this in your taplate:
<div id="sidebar">
{{ render(controller('YourBundle:User:login')) }}
</div>
This will inject whole output of YourBundle/UserController/loginAction to the #sidebar div. Remember that YourBundle/UserController/loginAction template can't extend other twig templates and hould be simple.
You can read more about embedding controllers here http://symfony.com/doc/current/book/templating.html#embedding-controllers
[EXAMPLE]:
An form action:
/**
* #Route("/contact", name="contact")
*/
public function contactAction(Request $request){
$form = $this->createFormBuilder()
->setAction($this->generateUrl('contact'))
->add('email', 'email', array(
'constraints' => array(
new \Symfony\Component\Validator\Constraints\Email()
)
))
->add('add', 'submit')
->getForm()
;
if ($request->getMethod() == 'POST') {
$form->handleRequest($request);
if ($form->isValid()) {
//do whatever you want and redirect
return $this->redirect($this->generateUrl('homepage'));
}else{
// this must be a full page (extending from base tamplate)
// that show form and errors
return $this->render(
'YourBundle:ControllerName:contact_faild.html.twig',
array('form' => $form->createView())
);
}
}
return $this->render(
'YourBundle:ControllerName:contact.html.twig',
array('form' => $form->createView())
);
}
There must be action URL in form "->setAction($this->generateUrl('contact'))" because form should be handled on separate request.
Next a form template (YourBundle:ControllerName:contact.html.twig):
{{ form(form) }}
Then we need an extra template for showing form errors when something went wrong. That should extend base template and probably override place where form appear in the first time
A form with errors tempalte (YourBundle:ControllerName:contact_faild.html.twig):
{% extends '::base.html.twig' %}
{% block sidebar -%}
{{ form(form) }}
{% endblock sidebar %}
And base teplate:
(...)
{% block sidebar %}
<div id="sidebar">
{{ render(controller('ClickAdUserBundle:User:contact')) }}
</div>
{% endblock %}
(...)
read this
you will find some html/twig code, put that in a "login.html.twig" and include it where you want
If you're completly new to Symfony2 i can suggest the symfony2 symblock tutorial
You'll work with Doctrine 2, creating Forms and design them, Twig Layouts and all the other stuff while creating a little blog.
Taken from the example, you would create the form in your controller like this
// src/Blogger/BlogBundle/Controller/PageController.php
public function contactAction()
{
$enquiry = new Enquiry(); //This creates an Instance of the Entity you need for the form
$form = $this->createForm(new EnquiryType(), $enquiry);
$request = $this->getRequest();
if ($request->getMethod() == 'POST') {
$form->bindRequest($request);
if ($form->isValid()) {
// Perform some action, such as sending an email
// Redirect - This is important to prevent users re-posting
// the form if they refresh the page
return $this->redirect($this->generateUrl('BloggerBlogBundle_contact'));
}
}
return $this->render('BloggerBlogBundle:Page:contact.html.twig', array(
'form' => $form->createView()
));
}
and the form as .html.twig would look like this
{# src/Blogger/BlogBundle/Resources/views/Page/contact.html.twig #}
{% extends 'BloggerBlogBundle::layout.html.twig' %}
{% block title %}Contact{% endblock%}
{% block body %}
<header>
<h1>Contact symblog</h1>
</header>
<p>Want to contact symblog?</p>
<form action="{{ path('BloggerBlogBundle_contact') }}" method="post" {{ form_enctype(form) }} class="blogger">
{{ form_errors(form) }}
{{ form_row(form.name) }}
{{ form_row(form.email) }}
{{ form_row(form.subject) }}
{{ form_row(form.body) }}
{{ form_rest(form) }}
<input type="submit" value="Submit" />
</form>
{% endblock %}
I hardly suggest working through this tutorial to have a nice start with symfony2
Related
I call to form every route, so instead of all the time to do :
$form = $this->get('form.factory')->createNamed(UserType:class);
$form->handleRequest($request);
I call it from twig UserRegister.html.twig:
{{ render(controller('AppBundle:Security:register')) }}
and the twig:
{% if form.vars['errors'] is not empty %}
{{ form_errors(form) }}
{% endif %}
{{ form_start(form) }}
{{ form_end(form)
on the control it's:
public function registerAction(Request $request)
{
$form = $this->get('form.factory')->createNamed('register', UserType::class);
$form->handleRequest($request);
if ($form->isSubmitted() && $form->isValid()) {
$em = $this->getDoctrine()->getManager();
$em->persist($form->getData());
$em->flush();
$em->clear();
return $this->redirectToRoute('app.homepage');
}
return $this->render('#site_forms/UserRegister.html.twig', ['form' => $form->createView()]);
}
So what's the big problem?
on error it will show only the form!
the error should return this current page!
It seems you are rendering only form's twig on !isValid() case. Maybe it comes from here?
you could use $this->redirectToRoute($request->get('_route') to always redirect to current page.
I try to follow this link to install and create a form with CraueFormFlowBundle
CraueFormFlowBundle tutorial
i create the file
/src/AppBundle/Form/InterventoFlow.php
namespace AppBundle/Form;
use Craue\FormFlowBundle\Form\FormFlow;
use Craue\FormFlowBundle\Form\FormFlowInterface;
class InterventoFlow extends FormFlow {
protected function loadStepsConfig() {
return array(
array(
'label' => 'wheels',
'form_type' => 'AppBundle\Form\InterventoForm',
),
array(
'label' => 'engine',
'form_type' => 'AppBundle\Form\InterventoForm',
'skip' => function($estimatedCurrentStepNumber, FormFlowInterface $flow) {
return $estimatedCurrentStepNumber > 1 && !$flow->getFormData()->canHaveEngine();
},
),
array(
'label' => 'confirmation',
),
);
}
}
after i create
/src/AppBundle/Form/InterventoForm.php
<?php
/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
namespace AppBundle/Form;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\Form\Extension\Core\Type\TextType;
class InterventoForm extends AbstractType {
public function buildForm(FormBuilderInterface $builder, array $options) {
switch ($options['flow_step']) {
case 1:
$validValues = array(2, 4);
$builder->add('numberOfWheels', 'Symfony\Component\Form\Extension\Core\Type\ChoiceType', array(
'choices' => array_combine($validValues, $validValues),
'placeholder' => '',
));
break;
case 2:
// This form type is not defined in the example.
$builder->add('engine', 'TextType', array(
'placeholder' => 'prova',
));
break;
}
}
public function getBlockPrefix() {
return 'createIntervento';
}
}
after i create the service
services:
app.form.InterventoFlow:
class: AppBundle\Form\InterventoFlow
parent: craue.form.flow
and the controller
public function interventoAction(Request $request)
{
$formData = new Validate(); // Your form data class. Has to be an object, won't work properly with an array.
$flow = $this->get('AppBundle.form.InterventoFlow'); // must match the flow's service id
$flow->bind($formData);
// form of the current step
$form = $flow->createForm();
if ($flow->isValid($form)) {
$flow->saveCurrentStepData($form);
if ($flow->nextStep()) {
// form for the next step
$form = $flow->createForm();
} else {
// flow finished
$em = $this->getDoctrine()->getManager();
$em->persist($formData);
$em->flush();
$flow->reset(); // remove step data from the session
return $this->redirect($this->generateUrl('home')); // redirect when done
}
}
return $this->render('interventi/intervento.html.twig', array(
'form' => $form->createView(),
'flow' => $flow,
));
}
and my twig file
{% extends 'base.html.twig' %}
{% block body %}
<div>
Steps:
{% include '#CraueFormFlow/FormFlow/stepList.html.twig' %}
</div>
{{ form_start(form) }}
{{ form_errors(form) }}
{% if flow.getCurrentStepNumber() == 1 %}
<div>
When selecting four wheels you have to choose the engine in the next step.<br />
{{ form_row(form.numberOfWheels) }}
</div>
{% endif %}
{{ form_rest(form) }}
{% include '#CraueFormFlow/FormFlow/buttons.html.twig' %}
{{ form_end(form) }}
{% endblock %}
{% stylesheets '#CraueFormFlowBundle/Resources/assets/css/buttons.css' %}
<link type="text/css" rel="stylesheet" href="{{ asset_url }}" />
{% endstylesheets %}
always give me error
Attribute "autowire" on service "app.form.intervento" cannot be inherited from "_defaults" when a "parent" is set. Move your child definitions to a separate file or define this attribute explicitly in C:\xampp\htdocs\Myprject\app/config\services.yml (which is being imported from "C:\xampp\htdocs\Myprject\app/config\config.yml").
and if i comment
parent: craue.form.flow
You have requested a non-existent service "app.form.interventoFlow".
Try to dalete _defaults section from your service.yml file.
I am making the form which allow a user to select a img.
Symfony2.8 with sonataMediaBundle/
$form = $this->createFormBuilder($form)
->add('media',EntityType::class,array(
'expanded' => true,
'class' => "Application\Sonata\MediaBundle\Entity\Media"
}))
->add('save', SubmitType::class, array('label' => 'Create Post'))
->getForm();
in twig
{{form_widget(form.media)}}
However it shows the radio buttons with only the name of img.
○AAA.jpg ○BBB.jpg ○CCC.jpg ○DDD.jpg ('○' is radio button)
It is not good design for users.
I want to show the thumbnail of imgs here.
Is there good way to do this?
The easiest way i can imagine is to actually check the radio button with javascript.
Your Controller :
//src/AppBundle/Controller/YourController.php
public function yourAction()
{
$em = $this->getDoctrine()->getManager();
$medias = $em->getRepository('AppBundle:Media')->findAll();
$entity = new YourEntity();
$form = $this->createForm(YourEntityType::class, $entity);
if ($form->isSubmitted() && $form->isValid()) {
//... your logic
}
return $this->render('AppBundle::template.html.twig', array(
'form' => $form->createView(),
'medias' => $medias
));
}
Then in your twig file
{% for media in medias %}
<img class="to-select" src="{{ media.pathToThumbnail }}" data-id="{{ media.id }}" />
{% endfor %}
{{ form_start(form) }}
<!-- assuming you are using bootstrap -->
<div class="hidden">{{ form_widget(form.media) }}</div>
{{ form_widget(form.submit) }}
{{ form_end(form) }}
{% block javascripts %}
<script>
//assuming you use jquery
$('.to-select').click(function () {
var id = '#form_name_media_' + $(this).data('id');
var media = $(id);
if (media.is(':checked')) {
media.prop('checked', false);
} else {
media.prop('checked', true);
}
});
</script>
{% endblock javascripts %}
[Entity file][1]
Controller
thx for your help
In Controller
$images = array();
$em = $this->getDoctrine->getManager();
$probleme = $em->getRepository('PiCrowdRiseWebBundle:Probleme')->findAll();
foreach ($probleme as $key => $entity) {
$images[$key] = base64_encode(stream_get_contents($entity->getFoto()));
}
// ...
return $this->render('PiCrowdRiseWebBundle:Probleme:problemList.html.twig', array(
'problemes' => $probleme,
'images' => $images,
));
View:
{% for key, entity in problemes %}
{# ... #}
<img alt="Embedded Image" src="data:image/png;base64,{{ images[key] }}" />
{# ... #}
{% endfor %}
Im new to Symfony2 / twig and I need to render a form with pre-saved values.
I can get the form to load / save data but I cant get it to show the pre-saved values. What am I missing?
Here is my controller code:
/**
* #Route("/build/{id}")
* #Template()
*/
public function buildAction($id)
{
$request = $this->getRequest();
$em = $this->getDoctrine()->getEntityManager();
$repo = $em->getRepository('ImagineNewsletterBundle:Section');
$section = $repo->find($id);
$newsletter = $section->getNewsletter();
$globalMag = $newsletter->getMagazine();
//$globalMag = unserialize($globalMag[0]);
$builder = $this->get('newsletter.builders')->getBuilder($section->getBuilder());
$builder->setSearchUrl($this->generateUrl('imagine_newsletter_section_search', array('builder' => $section->getBuilder())));
$form = $this->createForm($builder->getSearchFormBuilder());
$prevArticles = $section->getArticles();
// $form->bind($prevArticles);
return $this->render('ImagineNewsletterBundle:Section:'.$builder->getTemplate() , array('prevArticles' => $prevArticles,'builder' => $builder, 'form' => $form->createView(), 'section' => $section, 'newsletter' => $newsletter, 'globalmag' => $globalMag));
}
Here my twig/form code:
<form id="advert" action="{{ addAticle }}" method="post" {{ form_enctype(form) }} class="form-stacked">
<div class="form_element">
{{ form_label(form.topLogoAdvert) }}
{{ form_errors(form.topLogoAdvert) }}
{{ form_widget(form.topLogoAdvert) }}
</div>
<div class="form_element">
{{ form_label(form.topLogoAlt) }}
{{ form_errors(form.topLogoAlt) }}
{{ form_widget(form.topLogoAlt) }}
</div>
<div class="form_element">
{{ form_label(form.topLogoLink) }}
{{ form_errors(form.topLogoLink) }}
{{ form_widget(form.topLogoLink) }}
</div>
<input type="hidden" name="section" value="{{ section.id }}" />
{{ form_widget(form) }}
<div class="well">
<button type="submit" class="btn primary">Save</button>
<button id="reset" type="reset" class="btn">Reset</button>
</div>
{{ form_rest(form) }}
</form>
You need to bind the form to the request, that will then populate the form with the data the user entered. I have updated your code.
$request = $this->getRequest();
$em = $this->getDoctrine()->getEntityManager();
$repo = $em->getRepository('ImagineNewsletterBundle:Section');
$section = $repo->find($id);
$builder = $this->get('newsletter.builders')->getBuilder($section->getBuilder());
$builder->setSearchUrl($this->generateUrl('imagine_newsletter_section_search', array('builder' => $section->getBuilder())));
$form = $this->createForm($builder->getSearchFormBuilder(), $section);
if ($request->isMethod('post')) {
$form->bind($request);
}
return $this->render('ImagineNewsletterBundle:Section:'.$builder->getTemplate() , array('builder' => $builder, 'form' => $form->createView(), 'section' => $section));
You also need to ensure that when the form is submitted by the user that it goes to the action that output the form. I suspect now that you have a separate action to process the form.
Create a custom FormType http://symfony.com/doc/current/cookbook/form/create_custom_field_type.html
Fill your entity with the data you want and pass it to the form. (From database/staticly/api/etc.)
Then follow this existing answer on how to get data from the entity to the form so that when you display the form you can create existing values: How to pass entity atribute value to form Symfony2? Of course instead of the attribute type you make it a default choice.